ANR类型
出现ANR的一般有以下几种类型:
1:KeyDispatchTimeout(常见)
input事件在5S内没有处理完成发生了ANR。
logcat日志关键字:Input event dispatching timed out
2:BroadcastTimeout
前台Broadcast:onReceiver在10S内没有处理完成发生ANR。
后台Broadcast:onReceiver在60s内没有处理完成发生ANR。
logcat日志关键字:Timeout of broadcast BroadcastRecord
3:ServiceTimeout
前台Service:onCreate,onStart,onBind等生命周期在20s内没有处理完成发生ANR。
后台Service:onCreate,onStart,onBind等生命周期在200s内没有处理完成发生ANR
logcat日志关键字:Timeout executing service
4:ContentProviderTimeout
ContentProvider 在10S内没有处理完成发生ANR。 logcat日志关键字:timeout publishing content providers
| state=S scheds
tat=( 757205342094 583547320723 2145008 ) utm=52002 stm=23718 core=5 HZ=100
| stack=0x7fdc995000-0x7fdc997000 stackSize=8MB
| held mutexes=
kernel: __switch_to+0xb0/0xbc
kernel: SyS_epoll_wait+0x288/0x364
kernel: SyS_epoll_pwait+0xb0/0x124
kernel: cpu_switch_to+0x38c/0x2258
native: #00 pc 000000000007cd8c /system/lib64/libc.so (__epoll_pwait+8)
native: #01 pc 0000000000014d48 /system/lib64/libutils.so (android::Looper::pollInner(int)+148)
native: #02 pc 0000000000014c18 /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+60)
native: #03 pc 0000000000127474 /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)
at android.os.MessageQueue.nativePollOnce(Native method)
at android.os.MessageQueue.next(MessageQueue.java:330)
at android.os.Looper.loop(Looper.java:169)
at com.android.server.SystemServer.run(SystemServer.java:508)
at com.android.server.SystemServer.main(SystemServer.java:340)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:536)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:856)
…省略N行…
“OkHttp ConnectionPool” daemon prio=5 tid=251 TimedWaiting
| group=“main” sCount=1 dsCount=0 flags=1 obj=0x13daea90 self=0x7bad32b400
| sysTid=29998 nice=0 cgrp=default sched=0/0 handle=0x7b7d2614f0
| state=S schedstat=( 951407 137448 11 ) utm=0 stm=0 core=3 HZ=100
| stack=0x7b7d15e000-0x7b7d160000 stackSize=1041KB
| held mutexes=
at java.lang.Object.wait(Native method)
waiting on <0x05e5732e> (a com.android.okhttp.ConnectionPool)
at com.android.okhttp.ConnectionPool$1.run(ConnectionPool.java:103)
locked <0x05e5732e> (a com.android.okhttp.ConnectionPool)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
如上日志所示,本文截图了两个线程信息,一个是主线程main,它的状态是native。
另一个是OkHttp ConnectionPool,它的状态是TimeWaiting。众所周知,教科书上说线程状态有5种:新建、就绪、执行、阻塞、死亡。而Java中的线程状态有6种,6种状态都定义在:java.lang.Thread.State中
**问题来了,上述main线程的native是什么状态,哪来的?**其实trace文件中的状态是是CPP代码中定义的状态,下面是一张对应关系表。
由此可知,main函数的native状态是正在执行JNI函数。堆栈信息是我们分析ANR的第一个重要的信息,一般来说:
main线程处于 BLOCK、WAITING、TIMEWAITING状态,那基本上是函数阻塞导致ANR;
如果main线程无异常,则应该排查CPU负载和内存环境。
trace文件分析
拿到 trace 文件,详细分析下:
----- pid 7761 at 2022-11-02 07:02:26 -----
Cmd line: com.xfhy.watchsignaldemo
Build fingerprint: 'HUAWEI/LYA-AL00/HWLYA:10/HUAWEILYA-AL00/10.1.0.163C00:user/release-keys'
ABI: 'arm64'
Build type: optimized
Zygote loaded classes=11918 post zygote classes=729
Dumping registered class loaders
#0 dalvik.system.PathClassLoader: [], parent #1
#1 java.lang.BootClassLoader: [], no parent
#2 dalvik.system.PathClassLoader: [/system/app/FeatureFramework/FeatureFramework.apk], no parent
#3 dalvik.system.PathClassLoader: [/data/app/com.xfhy.watchsignaldemo-4tkKMWojrpHAf-Q3iecaHQ==/base.apk:/data/app/com.xfhy.watchsignaldemo-4tkKMWojrpHAf-Q3iecaHQ==/base.apk!classes2.dex:/data/app/com.xfhy.watchsignaldemo-4tkKMWojrpHAf-Q3iecaHQ==/base.apk!classes4.dex:/data/app/com.xfhy.watchsignaldemo-4tkKMWojrpHAf-Q3iecaHQ==/base.apk!classes3.dex], parent #1
Done dumping class loaders
Intern table: 44132 strong; 436 weak
JNI: CheckJNI is off; globals=681 (plus 67 weak)
Libraries: /data/app/com.xfhy.watchsignaldemo-4tkKMWojrpHAf-Q3iecaHQ==/lib/arm64/libwatchsignaldemo.so libandroid.so libcompiler_rt.so libhitrace_jni.so libhiview_jni.so libhwapsimpl_jni.so libiAwareSdk_jni.so libimonitor_jni.so libjavacore.so libjavacrypto.so libjnigraphics.so libmedia_jni.so libopenjdk.so libsoundpool.so libwebviewchromium_loader.so (15)
//已分配堆内存大小26M,其中2442kb医用,总分配74512个对象
Heap: 90% free, 2442KB/26MB; 74512 objects
Total number of allocations 120222 //进程创建到现在一共创建了多少对象
Total bytes allocated 10MB //进程创建到现在一共申请了多少内存
Total bytes freed 8173KB //进程创建到现在一共释放了多少内存
Free memory 23MB //不扩展堆的情况下可用的内存
Free memory until GC 23MB //GC前的可用内存
Free memory until OOME 381MB //OOM之前的可用内存,这个值很小的话,说明已经处于内存紧张状态,app可能是占用了过多的内存
Total memory 26MB //当前总内存(已用+可用)
Max memory 384MB //进程最多能申请的内存
.....//省略GC相关信息
//当前进程共17个线程
DALVIK THREADS (17):
//Signal Catcher线程调用栈
"Signal Catcher" daemon prio=5 tid=4 Runnable
| group="system" sCount=0 dsCount=0 flags=0 obj=0x18c84570 self=0x7252417800
| sysTid=7772 nice=0 cgrp=default sched=0/0 handle=0x725354ad50
| state=R schedstat=( 16273959 1085938 5 ) utm=0 stm=1 core=4 HZ=100
| stack=0x7253454000-0x7253456000 stackSize=991KB
| held mutexes= "mutator lock"(shared held)
native: #00 pc 000000000042f8e8 /apex/com.android.runtime/lib64/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, int, BacktraceMap*, char const*, art::ArtMethod*, void*, bool)+140)
native: #01 pc 0000000000523590 /apex/com.android.runtime/lib64/libart.so (art::Thread::DumpStack(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, bool, BacktraceMap*, bool) const+508)
native: #02 pc 000000000053e75c /apex/com.android.runtime/lib64/libart.so (art::DumpCheckpoint::Run(art::Thread*)+844)
native: #03 pc 000000000053735c /apex/com.android.runtime/lib64/libart.so (art::ThreadList::RunCheckpoint(art::Closure*, art::Closure*)+504)
native: #04 pc 0000000000536744 /apex/com.android.runtime/lib64/libart.so (art::ThreadList::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, bool)+1048)
native: #05 pc 0000000000536228 /apex/com.android.runtime/lib64/libart.so (art::ThreadList::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits<char>>&)+884)
native: #06 pc 00000000004ee4d8 /apex/com.android.runtime/lib64/libart.so (art::Runtime::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits<char>>&)+196)
native: #07 pc 000000000050250c /apex/com.android.runtime/lib64/libart.so (art::SignalCatcher::HandleSigQuit()+1356)
native: #08 pc 0000000000501558 /apex/com.android.runtime/lib64/libart.so (art::SignalCatcher::Run(void*)+268)
native: #09 pc 00000000000cf7c0 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+36)
native: #10 pc 00000000000721a8 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64)
(no managed stack frames)
"main" prio=5 tid=1 Sleeping
| group="main" sCount=1 dsCount=0 flags=1 obj=0x73907540 self=0x725f010800
| sysTid=7761 nice=-10 cgrp=default sched=1073741825/2 handle=0x72e60080d0
| state=S schedstat=( 281909898 5919799 311 ) utm=20 stm=7 core=4 HZ=100
| stack=0x7fca180000-0x7fca182000 stackSize=8192KB
| held mutexes=
at java.lang.Thread.sleep(Native method)
- sleeping on <0x00f895d9> (a java.lang.Object)
at java.lang.Thread.sleep(Thread.java:443)
- locked <0x00f895d9> (a java.lang.Object)
at java.lang.Thread.sleep(Thread.java:359)
at android.os.SystemClock.sleep(SystemClock.java:131)
at com.xfhy.watchsignaldemo.MainActivity.makeAnr(MainActivity.kt:35)
at java.lang.reflect.Method.invoke(Native method)
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:441)
at android.view.View.performClick(View.java:7317)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1219)
at android.view.View.performClickInternal(View.java:7291)
at android.view.View.access$3600(View.java:838)
at android.view.View$PerformClick.run(View.java:28247)
at android.os.Handler.handleCallback(Handler.java:900)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:219)
at android.app.ActivityThread.main(ActivityThread.java:8668)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109)
... //此处省略剩余的N个线程
trace 参数详细解读:
“Signal Catcher” daemon prio=5 tid=4 Runnable
| group=“system” sCount=0 dsCount=0 flags=0 obj=0x18c84570 self=0x7252417800
| sysTid=7772 nice=0 cgrp=default sched=0/0 handle=0x725354ad50
| state=R schedstat=( 16273959 1085938 5 ) utm=0 stm=1 core=4 HZ=100
| stack=0x7253454000-0x7253456000 stackSize=991KB
| held mutexes= “mutator lock”(shared held)
第1行:“Signal Catcher” daemon prio=5 tid=4 Runnable
“Signal Catcher” daemon:线程名,有 daemon 表示守护线程
prio:线程优先级
tid:线程内部 id
线程状态:Runnable
ps:一般来说,main线程处于 BLOCK、WAITING、TIMEWAITING 状态,基本上是函数阻塞导致的 ANR,如果 main 线程无异常,则应该排查 CPU 负载和内存环境。
第2行:| group=“system” sCount=0 dsCount=0 flags=0 obj=0x18c84570 self=0x7252417800
group:线程所属的线程组
sCount:线程挂起次数
dsCount:用于调试的线程挂起次数
obj:当前线程关联的 Java 线程对象
self:当前线程地址
第3行:| sysTid=7772 nice=0 cgrp=default sched=0/0 handle=0x725354ad50
sysTid:线程真正意义上的 tid
nice:调度优先级,值越小则优先级越高
cgrp:进程所属的进程调度组
sched:调度策略
handle:函数处理地址
第4行:| state=R schedstat=( 16273959 1085938 5 ) utm=0 stm=1 core=4 HZ=100
state:线程状态
schedstat:CPU调度时间统计(schedstat 括号中的3个数字依次是Running、Runable、Switch,Running 时间:CPU 运行的时间,单位 ns,Runable 时间:RQ 队列的等待时间,单位 ns,Switch 次数:CPU 调度切换次数)
utm/stm:用户态/内核态的 CPU 时间
core:该线程的最后运行所在核
HZ:时钟频率
第5行:| stack=0x7253454000-0x7253456000 stackSize=991KB
stack:线程栈的地址区间
stackSize:栈的大小
第6行:| held mutexes= “mutator lock”(shared held)
mutex:所持有 mutex 类型,有独占锁 exclusive 和共享锁 shared 两类
五、典型案例分析
5.1 主线程无卡顿,处于正常状态堆栈
“main” prio=5 tid=1 Native
| group=“main” sCount=1 dsCount=0 flags=1 obj=0x74b38080 self=0x7ad9014c00
| sysTid=23081 nice=0 cgrp=default sched=0/0 handle=0x7b5fdc5548
| state=S schedstat=( 284838633 166738594 505 ) utm=21 stm=7 core=1 HZ=100
| stack=0x7fc95da000-0x7fc95dc000 stackSize=8MB
| held mutexes=
kernel: __switch_to+0xb0/0xbc
kernel: SyS_epoll_wait+0x288/0x364
kernel: SyS_epoll_pwait+0xb0/0x124
kernel: cpu_switch_to+0x38c/0x2258
native: #00 pc 000000000007cd8c /system/lib64/libc.so (__epoll_pwait+8)
native: #01 pc 0000000000014d48 /system/lib64/libutils.so (android::Looper::pollInner(int)+148)
native: #02 pc 0000000000014c18 /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+60)
native: #03 pc 00000000001275f4 /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)
at android.os.MessageQueue.nativePollOnce(Native method)
at android.os.MessageQueue.next(MessageQueue.java:330)
at android.os.Looper.loop(Looper.java:169)
at android.app.ActivityThread.main(ActivityThread.java:7073)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:536)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:876)
上述主线程堆栈就是一个很正常的空闲堆栈,表明主线程正在等待新的消息。
如果ANR日志里主线程是这样一个状态,那可能有两个原因:
该ANR是CPU抢占或内存紧张等其他因素引起
这份ANR日志抓取的时候,主线程已经恢复正常
遇到这种空闲堆栈,可以按照第3节的方法去分析CPU、内存的情况。其次可以关注抓取日志的时间和ANR发生的时间是否相隔过久,时间过久这个堆栈就没有分析意义了。
5.2 主线程执行耗时操作
“main” prio=5 tid=1 Runnable
| group=“main” sCount=0 dsCount=0 flags=0 obj=0x72deb848 self=0x7748c10800
| sysTid=8968 nice=-10 cgrp=default sched=0/0 handle=0x77cfa75ed0
| state=R schedstat=( 24783612979 48520902 756 ) utm=2473 stm=5 core=5 HZ=100
| stack=0x7fce68b000-0x7fce68d000 stackSize=8192KB
| held mutexes= “mutator lock”(shared held)
at com.example.test.MainActivity$onCreate
2.
o
n
C
l
i
c
k
(
M
a
i
n
A
c
t
i
v
i
t
y
.
k
t
:
20
)
——关键行!!!
a
t
a
n
d
r
o
i
d
.
v
i
e
w
.
V
i
e
w
.
p
e
r
f
o
r
m
C
l
i
c
k
(
V
i
e
w
.
j
a
v
a
:
7187
)
a
t
a
n
d
r
o
i
d
.
v
i
e
w
.
V
i
e
w
.
p
e
r
f
o
r
m
C
l
i
c
k
I
n
t
e
r
n
a
l
(
V
i
e
w
.
j
a
v
a
:
7164
)
a
t
a
n
d
r
o
i
d
.
v
i
e
w
.
V
i
e
w
.
a
c
c
e
s
s
3500
(
V
i
e
w
.
j
a
v
a
:
813
)
a
t
a
n
d
r
o
i
d
.
v
i
e
w
.
V
i
e
w
3500
(
V
i
e
w
.
j
a
v
a
:
813
)
a
t
a
n
d
r
o
i
d
.
v
i
e
w
.
V
i
e
w
3500
(
V
i
e
w
.
j
a
v
a
:
813
)
a
t
a
n
d
r
o
i
d
.
v
i
e
w
.
V
i
e
w
P
e
r
f
o
r
m
C
l
i
c
k
.
r
u
n
(
V
i
e
w
.
j
a
v
a
:
27640
)
a
t
a
n
d
r
o
i
d
.
o
s
.
H
a
n
d
l
e
r
.
h
a
n
d
l
e
C
a
l
l
b
a
c
k
(
H
a
n
d
l
e
r
.
j
a
v
a
:
883
)
a
t
a
n
d
r
o
i
d
.
o
s
.
H
a
n
d
l
e
r
.
d
i
s
p
a
t
c
h
M
e
s
s
a
g
e
(
H
a
n
d
l
e
r
.
j
a
v
a
:
100
)
a
t
a
n
d
r
o
i
d
.
o
s
.
L
o
o
p
e
r
.
l
o
o
p
(
L
o
o
p
e
r
.
j
a
v
a
:
230
)
a
t
a
n
d
r
o
i
d
.
a
p
p
.
A
c
t
i
v
i
t
y
T
h
r
e
a
d
.
m
a
i
n
(
A
c
t
i
v
i
t
y
T
h
r
e
a
d
.
j
a
v
a
:
7725
)
a
t
j
a
v
a
.
l
a
n
g
.
r
e
f
l
e
c
t
.
M
e
t
h
o
d
.
i
n
v
o
k
e
(
N
a
t
i
v
e
m
e
t
h
o
d
)
a
t
c
o
m
.
a
n
d
r
o
i
d
.
i
n
t
e
r
n
a
l
.
o
s
.
R
u
n
t
i
m
e
I
n
i
t
2.onClick(MainActivity.kt:20)——关键行!!! at android.view.View.performClick(View.java:7187) at android.view.View.performClickInternal(View.java:7164) at android.view.View.access3500 ( V i e w . j a v a : 813 ) a t a n d r o i d . v i e w . V i e w 3500(View.java:813) at android.view.View3500(View.java:813)atandroid.view.ViewPerformClick.run(View.java:27640) at android.os.Handler.handleCallback(Handler.java:883) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:230) at android.app.ActivityThread.main(ActivityThread.java:7725) at java.lang.reflect.Method.invoke(Native method) at com.android.internal.os.RuntimeInit
2.onClick(MainActivity.kt:20)——关键行!!!atandroid.view.View.performClick(View.java:7187)atandroid.view.View.performClickInternal(View.java:7164)atandroid.view.View.access3500(View.java:813)atandroid.view.View3500(View.java:813)atandroid.view.View3500(View.java:813)atandroid.view.ViewPerformClick.run(View.java:27640)atandroid.os.Handler.handleCallback(Handler.java:883)atandroid.os.Handler.dispatchMessage(Handler.java:100)atandroid.os.Looper.loop(Looper.java:230)atandroid.app.ActivityThread.main(ActivityThread.java:7725)atjava.lang.reflect.Method.invoke(Nativemethod)atcom.android.internal.os.RuntimeInitMethodAndArgsCaller.run(RuntimeInit.java:526)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1034)
上述日志表明,主线程正处于执行状态,看堆栈信息可知不是处于空闲状态,发生ANR是因为一处click监听函数里执行了耗时操作。
5.3 主线程被锁阻塞
“main” prio=5 tid=1 Blocked
| group=“main” sCount=1 dsCount=0 flags=1 obj=0x72deb848 self=0x7748c10800
| sysTid=22838 nice=-10 cgrp=default sched=0/0 handle=0x77cfa75ed0
| state=S schedstat=( 390366023 28399376 279 ) utm=34 stm=5 core=1 HZ=100
| stack=0x7fce68b000-0x7fce68d000 stackSize=8192KB
| held mutexes=
at com.example.test.MainActivity$onCreate$1.onClick(MainActivity.kt:15)
waiting to lock <0x01aed1da> (a java.lang.Object) held by thread 3 ——————关键行!!!
at android.view.View.performClick(View.java:7187)
at android.view.View.performClickInternal(View.java:7164)
at android.view.View.access3500 ( V i e w . j a v a : 813 ) a t a n d r o i d . v i e w . V i e w 3500(View.java:813) at android.view.View3500(View.java:813)atandroid.view.ViewPerformClick.run(View.java:27640)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:230)
at android.app.ActivityThread.main(ActivityThread.java:7725)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:526)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1034)
…省略N行…
“WQW TEST” prio=5 tid=3 TimeWating
| group=“main” sCount=1 dsCount=0 flags=1 obj=0x12c44230 self=0x772f0ec000
| sysTid=22938 nice=0 cgrp=default sched=0/0 handle=0x77391fbd50
| state=S schedstat=( 274896 0 1 ) utm=0 stm=0 core=1 HZ=100
| stack=0x77390f9000-0x77390fb000 stackSize=1039KB
| held mutexes=
at java.lang.Thread.sleep(Native method)
sleeping on <0x043831a6> (a java.lang.Object)
at java.lang.Thread.sleep(Thread.java:440)
locked <0x043831a6> (a java.lang.Object)
at java.lang.Thread.sleep(Thread.java:356)
at com.example.test.MainActivity$onCreate2 22thread$1.run(MainActivity.kt:22)
locked <0x01aed1da> (a java.lang.Object)————————————————————关键行!!!
at java.lang.Thread.run(Thread.java:919)
这是一个典型的主线程被锁阻塞的例子;
waiting to lock <0x01aed1da> (a java.lang.Object) held by thread 3
其中等待的锁是<0x01aed1da>,这个锁的持有者是线程 3。进一步搜索 “tid=3” 找到线程3, 发现它正在TimeWating。
那么ANR的原因找到了:线程3持有了一把锁,并且自身长时间不释放,主线程等待这把锁发生超时。在线上环境中,常见因锁而ANR的场景是SharePreference写入。
5.4 CPU被抢占
CPU usage from 0ms to 10625ms later (2020-03-09 14:38:31.633 to 2020-03-09 14:38:42.257):
543% 2045/com.alibaba.android.rimet: 54% user + 89% kernel / faults: 4608 minor 1 major ————关键行!!!
99% 674/android.hardware.camera.provider@2.4-service: 81% user + 18% kernel / faults: 403 minor
24% 32589/com.wang.test: 22% user + 1.4% kernel / faults: 7432 minor 1 major
…省略N行…
如上日志,第二行是钉钉的进程,占据CPU高达543%,抢占了大部分CPU资源,因而导致发生ANR。
5.5 内存紧张导致ANR
如果有一份日志,CPU和堆栈都很正常(不贴出来了),仍旧发生ANR,考虑是内存紧张。
从CPU第一行信息可以发现,ANR的时间点是2020-10-31 22:38:58.468—CPU usage from 0ms to 21752ms later (2020-10-31 22:38:58.468 to 2020-10-31 22:39:20.220)
接着去系统日志里搜索am_meminfo, 这个没有搜索到。再次搜索onTrimMemory,果然发现了很多条记录;
10-31 22:37:19.749 20733 20733 E Runtime : onTrimMemory level:80,pid:com.xxx.xxx:Launcher0
10-31 22:37:33.458 20733 20733 E Runtime : onTrimMemory level:80,pid:com.xxx.xxx:Launcher0
10-31 22:38:00.153 20733 20733 E Runtime : onTrimMemory level:80,pid:com.xxx.xxx:Launcher0
10-31 22:38:58.731 20733 20733 E Runtime : onTrimMemory level:80,pid:com.xxx.xxx:Launcher0
10-31 22:39:02.816 20733 20733 E Runtime : onTrimMemory level:80,pid:com.xxx.xxx:Launcher0
可以看出,在发生ANR的时间点前后,内存都处于紧张状态,level等级是80,查看Android API 文档;
/**
Level for {@link #onTrimMemory(int)}: the process is nearing the end
of the background LRU list, and if more memory isn’t found soon it will
be killed.
*/
static final int TRIM_MEMORY_COMPLETE = 80;
可知80这个等级是很严重的,应用马上就要被杀死,被杀死的这个应用从名字可以看出来是桌面,连桌面都快要被杀死,那普通应用能好到哪里去呢?
一般来说,发生内存紧张,会导致多个应用发生ANR,所以在日志中如果发现有多个应用一起ANR了,可以初步判定,此ANR与你的应用无关。
5.6 系统服务超时导致ANR
系统服务超时一般会包含BinderProxy.transactNative关键字,请看如下日志:
“main” prio=5 tid=1 Native
| group=“main” sCount=1 dsCount=0 flags=1 obj=0x727851e8 self=0x78d7060e00
| sysTid=4894 nice=0 cgrp=default sched=0/0 handle=0x795cc1e9a8
| state=S schedstat=( 8292806752 1621087524 7167 ) utm=707 stm=122 core=5 HZ=100
| stack=0x7febb64000-0x7febb66000 stackSize=8MB
| held mutexes=
kernel: __switch_to+0x90/0xc4
kernel: binder_thread_read+0xbd8/0x144c
kernel: binder_ioctl_write_read.constprop.58+0x20c/0x348
kernel: binder_ioctl+0x5d4/0x88c
kernel: do_vfs_ioctl+0xb8/0xb1c
kernel: SyS_ioctl+0x84/0x98
kernel: cpu_switch_to+0x34c/0x22c0
native: #00 pc 000000000007a2ac /system/lib64/libc.so (__ioctl+4)
native: #01 pc 00000000000276ec /system/lib64/libc.so (ioctl+132)
native: #02 pc 00000000000557d4 /system/lib64/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+252)
native: #03 pc 0000000000056494 /system/lib64/libbinder.so (android::IPCThreadState::waitForResponse(android::Parcel*, int*)+60)