167

アプリが ANR (Application Not Responding) をスローした場所を見つける方法はありますか。/data の traces.txt ファイルを調べたところ、アプリケーションのトレースが表示されています。これは、トレースで見たものです。

DALVIK THREADS:
"main" prio=5 tid=3 TIMED_WAIT
  | group="main" sCount=1 dsCount=0 s=0 obj=0x400143a8
  | sysTid=691 nice=0 sched=0/0 handle=-1091117924
  at java.lang.Object.wait(Native Method)
  - waiting on <0x1cd570> (a android.os.MessageQueue)
  at java.lang.Object.wait(Object.java:195)
  at android.os.MessageQueue.next(MessageQueue.java:144)
  at android.os.Looper.loop(Looper.java:110)
  at android.app.ActivityThread.main(ActivityThread.java:3742)
  at java.lang.reflect.Method.invokeNative(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:515)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
  at dalvik.system.NativeStart.main(Native Method)

"Binder Thread #3" prio=5 tid=15 NATIVE
  | group="main" sCount=1 dsCount=0 s=0 obj=0x434e7758
  | sysTid=734 nice=0 sched=0/0 handle=1733632
  at dalvik.system.NativeStart.run(Native Method)

"Binder Thread #2" prio=5 tid=13 NATIVE
  | group="main" sCount=1 dsCount=0 s=0 obj=0x433af808
  | sysTid=696 nice=0 sched=0/0 handle=1369840
  at dalvik.system.NativeStart.run(Native Method)

"Binder Thread #1" prio=5 tid=11 NATIVE
  | group="main" sCount=1 dsCount=0 s=0 obj=0x433aca10
  | sysTid=695 nice=0 sched=0/0 handle=1367448
  at dalvik.system.NativeStart.run(Native Method)

"JDWP" daemon prio=5 tid=9 VMWAIT
  | group="system" sCount=1 dsCount=0 s=0 obj=0x433ac2a0
  | sysTid=694 nice=0 sched=0/0 handle=1367136
  at dalvik.system.NativeStart.run(Native Method)

"Signal Catcher" daemon prio=5 tid=7 RUNNABLE
  | group="system" sCount=0 dsCount=0 s=0 obj=0x433ac1e8
  | sysTid=693 nice=0 sched=0/0 handle=1366712
  at dalvik.system.NativeStart.run(Native Method)

"HeapWorker" daemon prio=5 tid=5 VMWAIT
  | group="system" sCount=1 dsCount=0 s=0 obj=0x4253ef88
  | sysTid=692 nice=0 sched=0/0 handle=1366472
  at dalvik.system.NativeStart.run(Native Method)

----- end 691 -----

どこに問題があるかを調べるにはどうすればよいですか? トレース内のメソッドはすべて SDK メソッドです。

4

12 に答える 12

134

「メイン」スレッドで長時間の操作が行われると、ANR が発生します。これはイベント ループ スレッドであり、ビジー状態の場合、Android はアプリケーションでこれ以上 GUI イベントを処理できないため、ANR ダイアログをスローします。

現在、投稿されたトレースでは、メイン スレッドは正常に動作しているようで、問題はありません。MessageQueue でアイドル状態になり、別のメッセージが着信するのを待っています。あなたの場合、ANR は、スレッドを永久にブロックするものではなく、より長い操作である可能性が高いため、操作が終了した後にイベント スレッドが回復し、トレースが通過しました。 ANR の後。

ANR が発生した場所を検出するのは、それが永続的なブロック (たとえば、いくつかのロックを取得するデッドロック) の場合は簡単ですが、一時的な遅延の場合は困難です。まず、コードを調べて、脆弱な場所や長時間実行されている操作を探します。例としては、イベント スレッド内からのソケット、ロック、スレッド スリープ、およびその他のブロッキング操作の使用が挙げられます。これらすべてが別々のスレッドで発生することを確認する必要があります。問題がないようであれば、DDMS を使用してスレッド ビューを有効にします。これにより、アプリケーション内のすべてのスレッドがトレースと同様に表示されます。ANR を再現し、同時にメイン スレッドを更新します。これは、ANR の時点で何が起こっているかを正確に示しているはずです。

于 2009-04-01T20:59:06.267 に答える
107

API レベル 9以降でStrictModeを有効にできます。

StrictMode は、UI 操作が受信され、アニメーションが発生するアプリケーションのメイン スレッドで、偶発的なディスクまたはネットワーク アクセスを検出するために最もよく使用されます。アプリケーションのメイン スレッドの応答性を維持することで、ANR ダイアログがユーザーに表示されなくなります。

public void onCreate() {
    StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                           .detectAll()
                           .penaltyLog()
                           .penaltyDeath()
                           .build());
    super.onCreate();
}

使用penaltyLog()すると、アプリケーションを使用して違反が発生したときに adb logcat の出力を監視できます。

于 2011-07-29T09:00:19.987 に答える
84

どのタスクが UI スレッドを保持しているか疑問に思っています。トレース ファイルは、タスクを見つけるためのヒントを提供します。各スレッドの状態を調査する必要があります

糸の状態

  • running - アプリケーション コードの実行
  • 睡眠 - Thread.sleep() と呼ばれる
  • モニター - モニターロックの取得を待機中
  • 待機 - Object.wait() 内
  • native - ネイティブ コードの実行
  • vmwait - VM リソースを待機中
  • ゾンビ - スレッドは死につつあります
  • init - スレッドが初期化中 (これは表示されません)
  • starting - スレッドが始まろうとしています (これも表示されません)

SUSPENDED、MONITOR 状態に注目してください。監視状態は、どのスレッドが調査されているかを示し、スレッドの SUSPENDED 状態がおそらくデッドロックの主な原因です。

基本的な調査手順

  1. 「ロック待ち」を探す
    • モニター状態"Binder Thread #15" prio=5 tid=75 MONITORを見つけることができます
    • 「ロック待ち」が見つかればラッキー!
    • 例 : threadid=74 が保持する <0xblahblah> (com.foo.A) のロックを待機中
  2. 「tid=74」がタスクを保持していることがわかります。tid=74 に移動します
  3. tid=74 サスペンド状態かも!主な理由を見つけてください!

トレースには、常に「ロック待ち」が含まれているとは限りません。この場合、主な理由を見つけるのは困難です。

于 2014-07-15T15:03:37.917 に答える
15

私はここ数か月間 Android を学んでいるので、専門家とは言えませんが、ANR に関するドキュメントには本当にがっかりしています。

ほとんどのアドバイスは、それらを回避するか、コードを盲目的に調べて修正することを目的としているようですが、トレースを分析しても何も見つかりませんでした。

ANR ログで実際に探す必要があるのは 3 つあります。

1) デッドロック: スレッドが WAIT 状態にある場合、詳細を調べて、「heldby=」が誰であるかを見つけることができます。ほとんどの場合、それ自体が保持されますが、別のスレッドによって保持されている場合は、危険な兆候である可能性があります。そのスレッドを見て、それが何によって保持されているかを確認してください。何か問題が発生したことを示す明確な兆候であるループが見つかる場合があります。これはかなりまれですが、それが起こると悪夢になるので、最初のポイントです

2) メイン スレッド待機中: メイン スレッドが WAIT 状態にある場合は、別のスレッドによって保持されているかどうかを確認します。UI スレッドはバックグラウンド スレッドによって保持されるべきではないため、これは発生しないはずです。

これらのシナリオは両方とも、コードを大幅に作り直す必要があることを意味します。

3) メイン スレッドでの負荷の高い操作: これは ANR の最も一般的な原因ですが、特定して修正するのが難しい場合もあります。メインスレッドの詳細を見てください。スタック トレースを下にスクロールし、(アプリから)認識できるクラスが表示されるまでスクロールします。トレース内のメソッドを見て、これらの場所でネットワーク呼び出し、db 呼び出しなどを行っているかどうかを判断してください。

最後に、恥知らずに自分のコードをプラグインしてしまったことをお詫びします。https://github.com/HarshEvilGeek/Android-Log-Analyzerに書いた Python ログ アナライザーを使用できます。これにより、ログ ファイルが調べられ、ANR ファイルが開かれ、デッドロック、待機中のメイン スレッドの検索、エージェント ログでキャッチされていない例外の検索、比較的読みやすい方法ですべての例外の表示を画面に表示します。使用方法については、ReadMe ファイル (これから追加します) を読んでください。先週は大変お世話になりました!

于 2014-08-08T07:14:57.177 に答える
4

タイミングの問題を分析しているときはいつでも、ブレークポイントでアプリをフリーズすると問題が解消されるため、デバッグは役に立たないことがよくあります。

最善の策は、アプリのさまざまなスレッドとコールバックに多数のロギング呼び出し (Log.XXX()) を挿入し、どこで遅延が発生しているかを確認することです。スタックトレースが必要な場合は、新しい例外を作成し (インスタンス化するだけ)、ログに記録します。

于 2011-02-18T20:26:54.617 に答える