诊断ANR的一般指南

时间:2015-03-09 09:01:45

标签: android android-anr-dialog

包含ANR痕迹文件有很多问题,答案总是“哦,问题出在你的主题76,修复你的http调用”或者其他东西:)但我找不到任何关于如何阅读的一般指南或教程对于任何ANR,这一步都是一步一步的。有没有?我特别提出几个问题:

  1. 总是可以从我在谷歌控制台中看到的真实ANR的线程痕迹中看到问题吗?或者是否可能没有相关信息,如果我不能在本地重现ANR,我运气不好?

  2. 此信息中包含哪些主题?我想应用程序进程中有所有线程,但其余的呢?它们在某种程度上与我相关吗? (例如我的一些线程正在等待的线程等)或者还有完全不相关的进程?

  3. Google Play控制台如何确定ANR发生的“地点” - 然后显示在ANR列表中,例如:

  4.   

    ANR keyDispatchingTimedOut

         

    miesto:com.sample.myapp / myapp.activities.SplashActivity

    因为SplashActivity在线程跟踪的提供文本中无处可见。

    1. 我知道我应该寻找WAIT状态下的线程来寻找潜在的死锁等等。线程在“等待自己”的情况怎么样?
    2.   

      “AsyncTask#1”prio = 5 tid = 15 WAIT | group =“main”sCount = 1 dsCount = 0   obj = 0x41bb50c0 self = 0x5529a868 | sysTid = 2448 nice = 0 sched = 0/0   cgrp = apps handle = 1429609576 | state = S schedstat =(18097077 39273309 41   )java.lang.Object.wait中的utm = 1 stm = 0 core = 1(本机方法)    - 等待< 0x41bb5258> (java.lang.VMThread)由tid = 15(AsyncTask#1)

      保存

      这总是好的,我可以认为这不是原因吗?那个情况怎么样,我在NATIVE中只有一堆线程(包括主线程)和WAIT中的一堆线程在这样等待自己?这怎么可能是ANR?

2 个答案:

答案 0 :(得分:4)

它可能不是检测您正在寻找的ANR的总体通用方法,但一个良好的开端是为您的应用程序启用严格模式。

您将能够检查logcat,系统会在您做错事时通知您。

只需将这些行添加到您的应用程序或活动的onCreate()方法中:

if (BuildConfig.DEBUG) {
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .detectDiskReads()
                .detectDiskWrites()
                .detectAll()
                .penaltyLog()
                .build());

        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                .detectLeakedSqlLiteObjects()
                .detectLeakedClosableObjects()
                .penaltyLog()
                .build());
    }

此处有更多详情:http://developer.android.com/reference/android/os/StrictMode.html

答案 1 :(得分:4)

系统向您的应用程序发送各种事件,这些事件在UI线程上接收。如果该线程在一段时间内没有响应事件,系统会断定应用程序没有响应,并启动ANR处理。

逐点解决你的问题:

  1. 并不总是可以在堆栈跟踪中看到问题。系统服务器进程检测到存在问题,然后通知有问题的进程转储其堆栈跟踪。如果应用程序在问题发现和堆栈转储信号之间恢复,则跟踪不会告诉您太多。

  2. 您应该会看到应用中的所有主题以及您的应用。 ANR机制不会尝试确定一组相关的"线程。开始的地方是UI线程,通常是app" main"线程,看看你是否因为卡住而抓住了它。有时候应用程序很慢,没有卡住,而且缓慢的原因实际上是一个不同的过程,即吸收CPU或磁盘带宽,但是你无法在堆栈跟踪中看到它......你可能会得到一个堆栈跟踪,反映执行过去的时间点"卡住"。

  3. "地点"是未响应的事件(在本例中为关键事件),以及系统尝试与之交互的活动。

  4. 这是正常的;当线程被停放时,你会看到#34;通过达尔维克的java.util.concurrent.locks.LockSupport.park()。请记住,在线程等待时释放锁定,因此在这种情况下,它只是等待另一个线程出现并通知它。

  5. 解决评论中提出的观点:如果(1)本机崩溃并未完全杀死应用程序,本机崩溃可能导致ANR,这就是它的原因应该做的; (2)死亡的线程是UI线程,或者拥有UI线程正在等待的资源。如果您无法访问完整的logcat,则可以检查线程列表以确认所有线程都处于活动状态。

    在查看ANR时,首先需要弄清楚的是它是永久卡住还是暂时放慢速度。对于使用该应用的人来说,这应该是显而易见的。永久冻结通常是最容易解决的,因为堆栈跟踪通常会引导您出错。从UI线程开始,遍历跟踪,直到找到一些在本机调用中旋转或卡住的代码。 (虽然它有本机调用的技巧 - 如果它说NATIVE然后它仍然在本机代码中,但如果它在堆栈顶部使用本机方法的线程上显示SUSPENDED,那么它&# 39;没有被卡住,而是从本机代码返回到托管代码。)

    瞬态ANR可能更难,特别是如果它们在配置未知的客户设备上发生。如果他们在后台运行CPU基准测试,因为闪存部件出现故障导致设备停止运行,那么您的应用将会遇到不好的时间。有时堆栈跟踪指向问题的一般方向(例如this one,其中显示缓慢渲染和粗略锁定停止UI线程),其他时候在应用程序恢复正常运行后捕获跟踪