分析Android上的ANR错误



在过去的一周里,我收到了11个非常类似的anr。我试着分析它们,但我没能看到代码的哪一部分导致ANR。

下面是其中一个堆栈转储:http://pastebin.com/rC8f3fgr

我认为anr总是由阻塞主线程引起的。然而,在转储中,我甚至找不到应用程序的主线程(com.degoo.android)。

唯一的事情我发现有点可疑的是,几个线程正在等待libwebviewchromium.so。我们不使用Chrome的webview做任何事情。但是,我们确实支持通过Google的oauth机制登录。也许是使用webview?

我该如何分析这样的问题呢?

这就是严格模式的作用:

if (DEVELOPER_MODE) {
         StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                 .detectDiskReads()
                 .detectDiskWrites()
                 .detectNetwork()   // or .detectAll() for all detectable problems
                 .penaltyLog()
                 .build());
         StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                 .detectLeakedSqlLiteObjects()
                 .detectLeakedClosableObjects()
                 .penaltyLog()
                 .penaltyDeath()
                 .build());
     }

一旦你启用了严格模式,应用程序就会卡在屏幕上,这会给UI线程带来更多的负载。

根据我的经验,anr是由涉及UI线程的死锁引起的。我猜你试图在anr开始之前同步你的应用程序使用资源的方式(如数据结构)。

我处理anr的最好方法:1. 在你的项目中搜索"synchronized("或"synchronized(")"(如果使用Android Studio,点击edit -> Search in file或在Eclipse中点击Search -> file)。2. 在每个同步块之前、内部和之后打印一些内容:

System.out.println("className.methodName() : capturing lock");
synchronized (lock) {
    System.out.println("className.methodName() : lock captured"); 
    ...
}
System.out.println("className.methodName() : lock released");
  • 运行并等待ANR。日志应该给你所有的数据,你需要知道什么时候和为什么这些anr发生。
  • 当同步方法中有同步块时要非常小心——在我的例子中,这是导致死锁的原因,因为UI线程可以捕获类锁并等待某些锁被释放,但是应该释放该锁的线程等待一般类级别的锁被释放,这被UI线程捕获,因此死锁。如果确实是这种情况,您可能希望避免同步方法,而只依赖同步块。

    希望有帮助

    最新更新