本文件說明如何在 ANR 堆疊傾印中找出無回應的執行緒。無回應的執行緒會因 ANR 類型而異,如下表所示。
ANR 類型 | 無回應的執行緒 |
---|---|
輸入調度 | 主執行緒 |
輸入調度無聚焦視窗 | 主執行緒。這類 ANR 通常不是因執行緒遭阻斷而造成。 |
廣播接收器 (同步) | 執行 onReceive() 的執行緒。除非使用 Context.registerReceiver 指定非主執行緒上的自訂處理常式,否則這會是主執行緒。 |
廣播接收器 (非同步) | 請查看程式碼,瞭解在呼叫 goAsync 後,是由哪個執行緒或執行緒集區負責處理廣播。 |
執行服務逾時 | 主執行緒 |
前景服務啟動 | 主執行緒 |
內容供應器沒有回應 | 以下兩者之一:
|
對 onStartJob 或 onStopJob 無回應 |
主執行緒 |
有時候,執行緒無回應是因為其他執行緒/程序中的根本問題。執行緒可能因等待以下項目而沒有回應:
- 由其他執行緒保留的鎖定。
- 對不同程序發出的緩慢繫結器呼叫。
導致執行緒無回應的常見原因
以下是導致執行緒無回應的常見原因。
繫結器呼叫速度緩慢
雖然大多數繫結器呼叫的速度都很快,但長尾呼叫可能非常慢。如果在載入裝置或繫結器回覆執行緒過慢時,例如因鎖定爭用、傳入許多繫結器呼叫,或硬體抽象層 (HAL) 逾時,就較可能出現這種情況。
如要解決這個問題,請盡可能將同步繫結器呼叫移至背景執行緒。如果呼叫必須在主執行緒上執行,請找出呼叫速度緩慢的原因。最佳做法是使用 Perfetto 追蹤記錄。
建議您在堆疊中尋找 BinderProxy.transactNative
或 Binderproxy.transact
,這表示繫結器呼叫正在執行。您可以依據這兩行程式碼,瞭解系統呼叫的繫結器 API 為何。在以下範例中,系統呼叫的是 IAccessibilityManager.addClient
。
main tid=123
...
android.os.BinderProxy.transactNative (Native method)
android.os.BinderProxy.transact (BinderProxy.java:568)
android.view.accessibility.IAccessibilityManager$Stub$Proxy.addClient (IAccessibilityManager.java:599)
...
連續多次發出繫結器呼叫
在緊密迴圈中連續多次執行繫結器呼叫,可能會長時間阻斷執行緒。
阻斷式 I/O
請勿在主執行緒上執行阻斷式 I/O,這屬於反模式。
鎖定爭用
如果執行緒在獲取鎖定時遭到阻斷,可能會導致 ANR。
以下是主執行緒在嘗試獲取鎖定時遭阻斷的例子:
main (tid=1) Blocked
Waiting for com.example.android.apps.foo.BarCache (0x07d657b7) held by
ptz-rcs-28-EDITOR_REMOTE_VIDEO_DOWNLOAD
[...]
at android.app.ActivityThread.handleStopActivity(ActivityThread.java:5412)
[...]
阻斷式執行緒正在提出 HTTP 要求來下載影片:
ptz-rcs-28-EDITOR_REMOTE_VIDEO_DOWNLOAD (tid=110) Waiting
at jdk.internal.misc.Unsafe.park(Native method:0)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:715)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1047)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:230)
at com.example.android.apps.foo.HttpRequest.execute(HttpRequest:136)
at com.example.android.apps.foo$Task$VideoLoadTask.downloadVideoToFile(RequestExecutor:711)
[...]
高成本影格
如果在單一影格中轉譯過多內容,可能會導致主執行緒在影格持續期間沒有回應,例如:
- 轉譯許多不必要的畫面外項目。
- 在轉譯許多 UI 元素時使用效率不佳的演算法,例如
O(n^2)
。
遭其他元件阻斷
如果廣播接收器等其他元件阻斷主執行緒的時間超過五秒,就可能導致輸入調度 ANR 和嚴重卡頓。
請避免在應用程式元件的主執行緒上執行大量作業,應盡可能在不同執行緒中執行廣播接收器。