
【前言】
【一. ANR定义与分类】
ANR全称Application Not Responding,意思就是程序未响应。如果应用程序在UI线程被阻塞太长时间,就会出现ANR。出现ANR,通常系统会弹出一个提示提示框。
(1). 广播ANR
(2). ServiceANR
(3). ContentProviderANR
(4). InputANR
(5). 系统WatchDog
ANR超时阈值
不同组件的超时阈值不同,Service、Broadcast、ContentProvider 、Input的超时阈值如下
(1)BroadcastTimeout
前台Broadcast:onReceiver在10S内没有处理完成发生ANR。
后台Broadcast:onReceiver在60s内没有处理完成发生ANR。
(3)ContentProviderTimeout
ContentProvider 在10S内没有处理完成发生ANR。
input事件在5S内没有处理完成(如按键或者触摸)发生了ANR。
【二. ANR产生原因与出现场景】
1. 产生ANR原因
a. 耗时操作
b. 自身服务阻塞
c. 系统阻塞
d. 内存紧张
e. CPU资源抢占
2. 典型场景
a. 主线程频繁进行耗时的IO操作:如数据库读写
b. 多线程操作的死锁,主线程被block;
c. 主线程被Binder 对端block;
d. SystemServer中WatchDog出现ANR;
e. servicebinder的连接达到上限无法和和System Server通信
f. 系统资源已耗尽(管道、CPU、IO)
【三. ANR定位与分析】
1. ANR分析思路——traces
trace路径:/data/anr/traces.txt
trace导出:adb pull/data/anr/traces.txt
在文件中使用ctrl + F 查找包名可以快速定位相关代码。特别注意:产生新的ANR,原来的 traces.txt 文件会被覆盖。
2. ANR其他分析思路与相关日志
分析logcat思路
分析kernel思路
分析cpuinfo思路
分析meminfo思路
3. traces.txt重要字段
main:main标识主线程,如果是线程,那么命名成“Thread-X”的格式,x表示线程id,逐步递增。
prio:线程优先级,默认是5
tid:tid不是线程的id,是线程唯一标识ID
group:是线程组名称
sCount:该线程被挂起的次数
dsCount:是线程被调试器挂起的次数
obj:对象地址
self:该线程Native的地址
sysTid:是线程号(主线程的线程号和进程号相同)
nice:是线程的调度优先级
sched:分别标志了线程的调度策略和优先级
cgrp:调度归属组
handle:线程处理函数的地址。
state:是调度状态
schedstat:从 /proc/[pid]/task/[tid]/schedstat读出,三个值分别表示线程在cpu上执行的时间、线程的等待时间和线程执行的时间片长度,不支持这项信息的三个值都是0;
utm:是线程用户态下使用的时间值(单位是jiffies)
stm:是内核态下的调度时间值
core:是最后执行这个线程的cpu核的序号。
找到java的堆栈信息定位代码位置,定位到问题。
【四. ANR分析案例】
分析案例一:Input ANR
分析案例二:在系统的方法上的锁没释放
WindowManagerGlobal.dumpGfxInfo
Blocked就一定有被持有的对象,这个有时候是发生在binder,就需要分析binder相关的log
分析案例三 内存问题
分析案例四 GC问题
观察Trace主线程堆栈,发现主线程在申请内存过程中被block,等待GC结束,
再看看其它线程状态,进一步查找发现,下面任务正在执行GC
Tid=8线程执行GC,导致主线程申请内存被Block,应用进程内存使用不当,导致GC时间过程,产生ANR。
【参考】
本文分享自微信公众号 - 搜狗测试(SogouQA)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。