AndroidANR之traces日志线程参数解析大全

连接轴
AndroidANR之traces⽇志线程参数解析⼤全
宁波溲疏ANR故障是Android开发中的重点难点问题,⽽⽇志的分析则是解决ANR问题的关键所在。有很多⼈对于⽇志中
的诸多线程状态参数⼀知半解,不知所云。本⽂章对这些状态参数结合源码进⾏全⾯的解读,相信对于解决ANR问题⼤有裨益(本⽂并不提
供解决ANR问题本⾝的思路和⽅法)。
执⾏ adb shell kill -3 pid或者当进程发⽣anr、native crash等故障的时候,系统会⽣成traces⽇志⽂件,默认输出到
/data/anr/ ⽬录下。traces⽇志主要由发⽣anr时的资源使⽤情况以及各个线程的状态组成。
----- pid 8072 at 2020-03-22 10:23:06 -----
Cmd line: amera
Build fingerprint: 'ZTE/GEN_CN_P439S01/P439S01:9/PKQ1.180929.001/20181106.134337:userdebug/test-keys'
ABI: 'arm'
...
Heap: 41% free, 11MB/20MB; 186365 objects
...
Total memory 20MB
Max memory 512MB
Zygote space size 1584KB
...
suspend all histogram: Sum: 191us 99% C.I. 4us-62us Avg: 21.222us Max: 62us
DALVIK THREADS (24):
"Signal Catcher" daemon prio=5 tid=3 Runnable
| group="system" sCount=0 dsCount=0 flags=0 obj=0x14540088 self=0xeb6cb200
| sysTid=8078 nice=0 cgrp=default sched=0/0 handle=0xe5dcb970
| state=R schedstat=( 59094373 1072863 12 ) utm=4 stm=1 core=4 HZ=100
| stack=0xe5cd0000-0xe5cd2000 stackSize=1010KB
| held mutexes= "mutator lock"(shared held)
native: #00 pc 002d975f  /system/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, int, BacktraceMap*, char cons  native: #01 pc 0036e91b  /system/lib/libart.so (art::Thread::DumpStack(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, bool, BacktraceMap*, bool  native: #02 pc 0036b0d3  /system/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, bool, BacktraceMap*, bool) cons  native: #03 pc 00383d89  /system/lib/libart.so (art::DumpCheckpoint::Run(art::Thread*)+624)
native: #04 pc 0037e06f  /system/lib/libart.so (art::ThreadList::RunCheckpoint(art::Closure*, art::Closure*)+314)
native: #05 pc 0037d767  /system/lib/libart.so (art::ThreadList::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, bool)+758)
native: #06 pc 0037d39f  /system/lib/libart.so (art::ThreadList::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits<char>>&)+614)
native: #07 pc 00357669  /system/lib/libart.so (art::Runtime::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits<char>>&)+120)
native: #08 pc 00360689  /system/lib/libart.so (art::SignalCatcher::HandleSigQuit()+1040)
native: #09 pc 0035f81b  /system/lib/libart.so (art::SignalCatcher::Run(void*)+246)
native: #10 pc 00071db1  /system/lib/libc.so (__pthread_start(void*)+22)
native: #11 pc 0001de65  /system/lib/libc.so (__start_thread+24)
(no managed stack frames)
"main" prio=5 tid=1 Native
| group="main" sCount=1 dsCount=0 flags=1 obj=0x74cb56d8 self=0xeb6ca000
| sysTid=8072 nice=-10 cgrp=default sched=0/0 handle=0xeffe9494
| state=S schedstat=( 1457862132 142332556 1571 ) utm=114 stm=31 core=4 HZ=100
| stack=0xff195000-0xff197000 stackSize=8MB
| held mutexes=
kernel: __switch_to+0x90/0xe8
kernel: futex_wait_queue_me+0xc4/0x13c
kernel: futex_wait+0xe4/0x204
kernel: do_futex+0x168/0x9a0
kernel: compat_SyS_futex+0xf0/0x174
kernel: __sys_trace+0x4c/0x4c
native: #00 pc 00019e8c  /system/lib/libc.so (syscall+28)
防砸鞋其中以下⽚段为线程的各项状态参数,是本⽂将要解析的部分。
"main" prio=5 tid=1 Native
| group="main" sCount=1 dsCount=0 flags=1 obj=0x74cb56d8 self=0xeb6ca000
| sysTid=8072 nice=-10 cgrp=default sched=0/0 handle=0xeffe9494
| state=S schedstat=( 1457862132 142332556 1571 ) utm=114 stm=31 core=4 HZ=100
| stack=0xff195000-0xff197000 stackSize=8MB
| held mutexes=
输出线程的状态参数所涉及的核⼼代码为Thread::DumpState函数(代码位于/art/⽂件),以下深⼊全⾯解析各⾏参数的涵义:
(1)"main" prio=5 tid=1 Native
"main"
线程名。"main"表⽰该线程为主线程;"Binder:8072_2"表⽰为线程与进程8072关联的Binder线程;"Signal Catcher" daemon表⽰为守护线程Signal Catcher。
os << '"' << *thread->tlsPtr_.name << '"';
prio=5
线程优先级。通过java.lang.Thread.setPriority设置,取值范围 [1, 10],低优先级 -> ⾼优先级。
os << " prio=" << priority
tid=1
进程内部线程id。取值⼀般⽐较⼩。
os << " tid=" << thread->GetThreadId();
Native
线程状态。具体取值及意义如下图。
os  << " " << thread->GetState();
(2)group="main" sCount=1 dsCount=0 flags=1 obj=0x74cb56d8 self=0xeb6ca000
group="main"
线程所属的线程组。Java中使⽤ThreadGroup来表⽰线程组,它可以对⼀批线程进⾏分类管理,Java允许程序直接对线程组进⾏控制。默认情况下,所有的线程都属于主线程组。我们也可以给线程设置分组。
os << "  | group=\"" << group_name << "\"";
sCount=1
线程挂起次数。
os << " sCount=" << thread->tls32_.suspend_count;
dsCount=0
⽤于调试的线程挂起次数。
os << " dsCount=" << thread->tls32_.debug_suspend_count;
flags=1
os << " flags=" << thread->tls32_.state_and_flags.as_struct.flags;
obj=0x74cb56d8
当前线程关联的java线程对象。
os << " obj=" << reinterpret_cast<void*>(thread->tlsPtr_.opeer);
self=0xeb6ca000
当前线程地址。
os << " self=" << reinterpret_cast<const void*>(thread) << "\n";
(3)sysTid=8072 nice=-10 cgrp=default sched=0/0 handle=0xeffe9494
sysTid=8072
线程号,Linux内核分配的id。在系统中是唯⼀编号的。
os << "  | sysTid=" << tid;
nice=-10
线程的调度优先级。通过android.os.Process.setThreadPriority设置,取值范围 [-20, 19],⾼优先级 -> 低优先级。
os << " nice=" << getpriority(PRIO_PROCESS, tid);
cgrp=default
程所属的进程调度组。Control groups,是Linux内核的⼀个功能,⽤来限制,控制与分离⼀个进程组的资源(如CPU、内存、磁盘输⼊输出等)。
os << " cgrp=" << scheduler_group_name;
sched=0/0
分别标志了线程的调度策略和优先级。
os << " sched=" << policy << "/" << sp.sched_priority;
handle=0xeffe9494
线程的处理函数地址。
os << " handle=" << reinterpret_cast<void*>(thread->tlsPtr_.pthread_self);
(4)state=S schedstat=( 1457862132 142332556 1571 ) utm=114 stm=31 core=4 HZ=100 state=S
线程的调度状态。
os << "  | state=" << native_thread_state;
schedstat=( 1457862132 142332556 1571 )
CPU调度时间统计,分别表⽰线程在cpu上执⾏的时间、线程的等待时间和线程执⾏的时间⽚长度。可通过adb shell cat
/proc/[pid]/task/[tid]/schedstat查看。
汽车电动踏板os << " schedstat=( " << scheduler_stats << " )";
utm=114 stm=31
⽤户态/内核态下使⽤CPU时间(单位是jiffies)。adb shell cat /proc/[pid]/task/[tid]/stat查看。
os << " utm=" << utime
<< " stm=" << stime;
core=4
最后执⾏该线程的cpu核的序号 。
os << " core=" << task_cpu;
HZ=100
全局变量jiffies⽤来记录⾃系统启动以来产⽣的中断总数。系统启动时,内核将该变量初始化为0,之后每次时钟中断处理程序都会增加该变量的值。⼀秒内时钟中断的次数等于Hz。Tick是HZ的倒数,表⽰每发⽣⼀次时钟中断所需的时间。HZ=100,那么Tick=10ms。每秒增加的jiffies数等于Hz。系统运⾏时间以秒为单位,等于jiffies/Hz。
os << " HZ=" << sysconf(_SC_CLK_TCK) << "\n";偶极子天线
(5)stack=0xff195000-0xff197000 stackSize=8MB
stack=0xff195000-0xff197000
线程栈的地址区间。
os << "  | stack=" << reinterpret_cast<void*>(thread->tlsPtr_.stack_begin) << "-"
<< reinterpret_cast<void*>(thread->tlsPtr_.stack_end);
stackSize=8MB
线程栈的⼤⼩。stack地址区间的距离(0xff197000-0xff195000 = 8192KB)。Android中主线程栈⼤⼩默认为8M,⼦线程栈⼤⼩稍微⼩于1M。
os << PrettySize(thread->tlsPtr_.stack_size) << "\n";
网上冲印系统
(6)held mutexes=
线程所持有mutex类型。分为独占锁exclusive和共享锁shared两类。

本文发布于:2024-09-21 19:39:22,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/3/154964.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:线程   问题   时间   解决   中断   状态参数
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议