第一个框中第一二行说明了发生ANR的进程ID,名称和时间
第三个框中
“main” prio=5 tid=1 Native
说明了线程名称,线程优先级,线程锁id和线程状态。tid不是线程id,是一个在Java虚拟机中用来实现线程锁的变量,线程状态分为以下几类:
状态 值 说明
THREAD_ZOMBIE 0 TERMINATED 线程死亡,终止运行
THREAD_RUNNING 1 RUNNABLE or running now 线程可运行或正在运行
THREAD_TIMED_WAIT 2 TIMED_WAITING in Object.wait() 执行了带有超时参数的wait,sleep或join参数
THREAD_MONITOR 3 BLOCKED on a monitor 线程阻塞,等待获取对象锁
THREAD_WAIT 4 执行了无超时参数的wait()函数
THREAD_INITIALIZING 5 allocated not yet running 新建,正在初始化,为其分配资源
THREAD_STARTING 6 started not yet on thread list 新建,正在启动
THREAD_NATIVE 7 off in a JNI native method 正在执行JNI本地函数
THREAD_VMWAIT 8 waiting on a VM resource 正在等待VM资源
THREAD_SUSPENDED 9 suspended usually by GC or debugger 线程暂停,通常是由于GC或者debug被暂停
特别说明线程状态为MONITOR和SUSPEND。MONITOR状态一般是类的同步块或者同步方法造成的,而SUSPEND状态是debugger的时候会出现,可以用来区别是不是真的是用户正常操作跑出来ANR
| group=“main” sCount=1 dsCount=0 flags=1 obj=0x74491f18 self=0xe5490000
后面一行group为线程组名称,sCount是线程被挂起的次数,dsCount是线程被调试器挂起的次数。当一个进程开始调试后sCount会变为0,调试结束判断是否被正常挂起进行增长,但是dsCount不会变为0,所以dsCount可以用来判断这个线程是否被调试过,obj为线程java对象的地址,self表示这个线程本身的地址
| sysTid=14761 nice=-10 cgrp=default sched=0/0 handle=0xe90e9494
在此后是线程的调度信息:sysTid是Linux下的内核线程ID,nice是线程的调度优先级,sched分别标志了线程的调度策略和优先级,cgrp是调度数组,handle是线程的处理函数地址
| state=S schedstat=( 808116553592 297347340368 970474 ) utm=71464 stm=9347 core=3 HZ=100
接着state是调度状态,utm是线程用户态下使用的时间值,stm是内核态下的调度时间值,core是最后执行这个线程的cpu核的序号
至此trace解析差不多完成。
大部分情况下trace文件顶部的线程一般是ANR的元凶,但是也有可能不是应用造成的ANR。
死锁和等待也会造成ANR,比如线程状态为MONITOR的时候正在执行一个同步块,但是锁却被另外一个线程拿着造成主线程阻塞(等待);死锁的分析也是类似,发生死锁的线程一般处于MONITOR状态或者WAIT状态,等待其他进程的锁或者monitor,而其他进程又在等待另外线程的锁或者monitor,一直这样依赖下去,直到形成一个环。
(参考链接:
1.https://blog.csdn.net/yxz329130952/article/details/50087731/
2.https://blog.csdn.net/lovelease/article/details/81988696
3.https://www.cnblogs.com/wanqieddy/archive/2013/12/26/3492373.html