Android - 如何调查ANR?

los*_*sit 145 performance android android-anr-dialog

有没有办法找出我的应用程序扔ANR(应用程序无响应)的位置.我看了/ 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 -----
Run Code Online (Sandbox Code Playgroud)

我怎样才能找出问题所在?跟踪中的方法都是SDK方法.

谢谢.

soo*_*iln 122

当在"主"线程中发生一些长操作时,会发生ANR.这是事件循环线程,如果它很忙,Android无法处理应用程序中的任何其他GUI事件,从而抛出ANR对话框.

现在,在您发布的跟踪中,主线程似乎做得很好,没有问题.它在MessageQueue中空闲,等待另一条消息进来.在你的情况下,ANR可能是一个更长的操作,而不是永久阻塞线程的东西,所以事件线程在操作完成后恢复,你的跟踪经历了在ANR之后.

如果ANR是永久性块(例如,死锁获取某些锁),则检测ANR发生的位置很容易,但如果它只是暂时的延迟则更难.首先,查看代码并查找可用的点和长时间运行的操作.示例可以包括在事件线程内使用套接字,锁,线程休眠和其他阻塞操作.你应该确保这些都发生在不同的线程中.如果没有任何问题,请使用DDMS并启用线程视图.这会显示应用程序中的所有线程与您拥有的跟踪类似.重现ANR,同时刷新主线程.这应该向你展示ANR时正在发生的事情

  • 堆栈跟踪显示主线程在Looper(消息循环实现)中并通过Object.wait进行定时等待.这意味着消息循环当前没有任何要分派的消息,并且正在等待新消息进入.当系统实现消息循环花费大量时间处理消息而不处理其他消息时,会发生ANR.队列.如果循环正在等待消息,显然这不会发生. (20认同)
  • 有关输出的详细说明,请参见http://elliotth.blogspot.com/2012/08/how-to-read-dalvik-sigquit-output.html. (6认同)
  • 唯一的问题是"重现ANR":-).你能解释一下堆栈跟踪显示主线程是"空闲"的,这会很棒. (5认同)
  • @Soonil嗨,你知道其余的部分意味着什么像Binder线程3,Binder线程2 JDWP恶魔prio 5.什么是sCount,dsCount,obj,sysTid,漂亮的sched意味着什么.它也有VMWAIT,RUNNABLE,NATIVE等信息 (3认同)

Dhe*_*.S. 95

您可以在API级别9及更高级别启用StrictMode.

StrictMode最常用于捕获应用程序主线程上的意外磁盘或网络访问,其中接收UI操作并进行动画.通过保持应用程序的主线程响应,您还可以防止向用户显示ANR对话框.

public void onCreate() {
    StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                           .detectAll()
                           .penaltyLog()
                           .penaltyDeath()
                           .build());
    super.onCreate();
}
Run Code Online (Sandbox Code Playgroud)

使用penaltyLog()您可以在使用应用程序时查看adb logcat的输出,以便在发生违规时查看违规行为.

  • 小提示 - 使用if(BuildConfig.DEBUG)...以防止包含在生产中 (22认同)
  • @MuhammedRefaat它不会阻止任何ANR.它会立即使应用程序崩溃,而不是在5秒后崩溃.例如,如果您在主线程上访问数据库并且需要2秒,那么您将无法获得ANR,但StrictMode将使应用程序崩溃.StrictMode严格用于您的调试阶段,而不是生产阶段. (2认同)

Hor*_*Lee 70

您想知道哪个任务持有UI线程.跟踪文件为您提供了查找任务的提示.你需要调查每个线程的状态

线程状态

  • 运行 - 执行应用程序代码
  • 睡觉 - 叫做Thread.sleep()
  • 监视器 - 等待获取监视器锁定
  • 等待 - 在Object.wait()
  • 原生 - 执行本机代码
  • vmwait - 等待VM资源
  • 僵尸 - 线程正在死亡
  • init - thread正在初始化(你不应该看到这个)
  • 开始 - 线程即将开始(你不应该看到这个)

专注于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也许是SUSPENDED状态!找主要原因!

跟踪并不总是包含"等待锁定".在这种情况下,很难找到主要原因.

  • 我在“HeapTaskDaemon”守护进程 prio=5 tid=8 Blocked 内有“- 等待锁定未知对象”。有人可以帮忙是什么意思? (2认同)

Akh*_*ese 12

我过去几个月一直在学习android,所以我远非专家,但我对ANR的文档感到非常失望.

大多数建议似乎都是为了避免它们或通过盲目查看代码来修复它们,这很好,但我找不到任何关于跟踪的分析.

使用ANR日志确实需要查找三件事.

1)死锁:当线程处于WAIT状态时,您可以查看详细信息以查找它的"holdby =".大多数情况下,它将由它自己保留,但如果它由另一个线程持有,那很可能是一个危险信号.去看看那个帖子,看看它的含义.你可能会发现一个循环,这是一个明显的迹象,表明出了问题.这是非常罕见的,但这是第一点,因为当它发生时,这是一场噩梦

2)主线程等待:如果你的主线程处于WAIT状态,检查它是否被另一个线程持有.这不应该发生,因为您的UI线程不应该由后台线程持有.

这两种情况都意味着您需要对代码进行重大修改.

3)主线程上的大量操作:这是ANR最常见的原因,但有时候难以找到并修复.看一下主要的线程细节.向下滚动堆栈跟踪,直到看到您识别的类(来自您的应用程序).查看跟踪中的方法,并确定您是否在这些地方进行网络呼叫,数据库呼叫等.

最后,我为无耻地插入我自己的代码而道歉,你可以使用我在https://github.com/HarshEvilGeek/Android-Log-Analyzer上写的python日志分析器这将查看你的日志文件,打开ANR文件,找到死锁,找到等待主线程,在代理日志中查找未捕获的异常,并以相对容易阅读的方式将其全部打印出来.阅读ReadMe文件(我即将添加)以了解如何使用它.它在上周给了我很多帮助!


phn*_*mnn 7

您需要在/data/anr/traces.txt文件中查找“等待锁定”

在此输入图像描述

了解更多详细信息:使用 Android 和 Play 工具实现高性能工程师 (Google I/O '17)


小智 5

每当您分析时序问题时,调试通常都无济于事,因为将应用程序冻结在断点将使问题消除。

最好的选择是将许多日志记录调用(Log.XXX())插入应用程序的不同线程和回调中,并查看延迟在哪里。如果需要堆栈跟踪,请创建一个新的Exception(只需实例化一个)并记录它。

  • 感谢您在需要堆栈跟踪时创建新异常的建议。这在调试时非常有用:) (2认同)