[关闭]
@ZeroGeek 2018-07-31T02:22:55.000000Z 字数 2942 阅读 1995

ANR定性分析与排查

Android高工成长之路


ANR是什么(Application Not Responding)

指应用程序(具体指应用组件)不能响应用户的操作。

Android应用运行在一个线程中(称为UI线程或主线程)。一但这个线程被阻塞时间过长,则无法响应用户的操作或intent broadcasts。系统不允许这种情况,所以系统会弹窗提示抛出ANR。

为什么会产生ANR

应用程序的响应是由ActivityManager和WindowManager等系统服务监视的,当检测到下面情况的任何一种时,Android就会针对特定的应用程序显示ANR对话框。

如何避免ANR

应在主线程做尽可能少的事情。耗时的工作(网络、数据库、大量计算、图片处理等)交给子线程处理。

推荐使用:

产生ANR的常见场景

如何预防ANR

开启StrictMode,检测主线程的I/O操作

运用Traceview工具

查看追踪的日志

老版本目录:/data/anr/traces.txt
新版本目录:/data/anr/anr_*

  1. adb root
  2. adb shell ls /data/anr
  3. adb pull /data/anr/<filename>

logcat日志分析

  1. 07-25 14:07:21.053 1471-29421/? E/ActivityManager: ANR in com.mymoney (com.mymoney/.biz.account.activity.SelectAccountOrgActivity)
  2. PID: 28867
  3. Reason: Input dispatching timed out (Waiting to send key event because the focused window has not finished processing all of the input events that were previously delivered to it. Outbound queue length: 0. Wait queue length: 2.), happend at time = 6940397@#@28867
  4. Load: 0.0 / 0.0 / 0.0
  5. CPU usage from 141511ms to 0ms ago with 99% awake:

这类问题是主线程正在执行其他的事件但是比较耗时导致输入事件无法及时处理。
同时看到CPU是满负荷情况,99% awake。
通常由Moneky跑出来的。

traces.txt分析

从设备中拷贝出ANR日志后,先找到应用ANR的位置:

  1. ----- pid 32758 at 2018-07-25 07:58:27 -----
  2. Cmd line: com.mymoney // 锁定包名

可以看到此时内存已经被占满

  1. Heap: 0% free, 127MB/128MB; 513576 objects

接下来主要分析主线程的情况

  1. DALVIK THREADS (71):
  2. "main" prio=5 tid=1 Waiting // 主线程,处于等待状态
  3. | group="main" sCount=2 dsCount=0 obj=0x758fe248 self=0xb4d07800
  4. | sysTid=32758 nice=-6 cgrp=apps sched=0/0 handle=0xb6f08ec8
  5. | state=S schedstat=( 0 0 0 ) utm=91621 stm=11873 core=1 HZ=100
  6. | stack=0xbe761000-0xbe763000 stackSize=8MB
  7. | held mutexes=
  8. at java.lang.Object.wait!(Native method)
  9. - waiting on <0x09315ca1> (a android.app.SharedPreferencesImpl)
  10. at android.app.SharedPreferencesImpl.awaitLoadedLocked(SharedPreferencesImpl.java:206)
  11. at android.app.SharedPreferencesImpl.getLong(SharedPreferencesImpl.java:245)
  12. - locked <0x09315ca1> (a android.app.SharedPreferencesImpl)
  13. at hgu.b(ExceptionHandler.java:63)
  14. at hgu.a(ExceptionHandler.java:56)
  15. at hgu.uncaughtException(ExceptionHandler.java:41)
  16. at com.flurry.sdk.od$a.uncaughtException(SourceFile:2088)
  17. at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
  18. at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)

第11行看到主线程执行了SharedPreference的getLong,并处于等待锁状态。因为SharedPreferencesImpl初始化时,会开启一个子线程从磁盘加载数据到内存中,此时会持有锁并阻塞其它线程的操作直到加载完成才释放锁。但是由于内存不足,会频繁触发GC操作,而GC操作又会阻塞其它所有线程的执行,从而导致主线程等待超时产生ANR。

如何解决这个问题呢?
1.整体上做内存优化
2.提前初始化SharedPreferencesImpl
3.减少SharedPreference的存储数据量

小结

拿到一份ANR的完整日志,一般步骤如下:

  1. 根据时间和进程找到应用ANR的具体日志位置(分析控制台日志)
  2. 查看CPU的使用情况和内存情况(分析控制台日志)
  3. 查看trace.txt文件,找到具体进程位置,查看内存(trace.txt)
  4. 查看主线程的线程状态和具体堆栈信息去分析(trace.txt)

参考链接

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注