Android开发之散记开发

性能优化(六):ANR问题分析

2022-02-18  本文已影响0人  w达不溜w

ANR (Application Not Responding)应用程序无响应。如果应用程序在UI线程处理阻塞状态的时间过长,会触发ANR。

Android系统中,ActivityManagerService(简称AMS)WindowManagerService(简称WMS)会检测App的响应时间,如果App在特定时间无法响应屏幕触摸或键盘输入事件,或者特定事件没有处理完毕,就会出现ANR。

官方文档:https://developer.android.google.cn/topic/performance/vitals/anr?hl=zh_cn

1、ANR类型

1、KeyDispatchTimeout (主要类型):

5s内未响应用户input事件(如键盘输入, 触摸屏幕等)

Logcat日志关键字:Input event dispatching timed out

2、BroadcastTimeout

前台Broadcast:onReceiver在10s内未处理完成

后台Broadcast:onReceiver在60s内未处理完成

Logcat日志关键字:Timeout of broadcast BroadcastRecord

3、ServiceTimeout

前台Service:onCreate,onStart,onBind等生命周期在20s内未处理完成

后台Service:onCreate,onStart,onBind等生命周期在200s内未处理完成

Logcat日志关键字:Timeout executing service

4、ContentProviderTimeout

10s内未处理完成

Logcat日志关键字:timeout publishing content providers

2、ANR原因

3、ANR日志分析

当App发生ANR时,系统会dump出一个traces文件,目录/data/anr

bestchanggedembp:~ sun$ adb shell
HWJER:/ $ cd data/anr
HWJER:/data/anr $ ls -a
.  anr_2022-02-15-12-48-17-616 dumptrace_ZlVIkw 
.. anr_2022-02-15-16-34-22-122 
HWJER:/data/anr $ exit
bestchanggedembp:~ sun$ adb pull data/anr/anr_2022-02-15-16-34-22-122
adb: error: failed to copy 'data/anr/anr_2022-02-15-16-34-22-122' to './anr_2022-02-15-16-34-22-122': remote open failed: Permission denied
bestchanggedembp:~ sun$ adb bugreport
/data/user_de/0/com.android.shell/file.... 36.4 MB/s (10895407 bytes in 0.285s)

先查看是否存在traces(有的手机厂商会根据时间戳生成一个文件),pull失败则用adb bugreport

此命令会导出一个压缩包,解压后在FS/data/anr下可以看到traces文件了。

traces参数解读:

//"main"表示主线程调用栈    prio:线程优先级  tid:线程内部id  Runnable:表线程状态Runnable
"main" prio=5 tid=1 Runnable
    //group:线程所属的线程组    sCount:线程挂起次数   dsCount:用于调试的线程挂起次数 obj:当前线程关联的java线程对象 self:当前线程地址 
  | group="main" sCount=0 dsCount=0 flags=0 obj=0x73cebe98 self=0xb4000077f1e9ec00
  //sysTid:线程真正意义上的tid  nice:调度优先级  cgrp:进程所属的进程调度组 sched:调度策略  handle:函数处理地址 
  | sysTid=23569 nice=-10 cgrp=default sched=0/0 handle=0x77f34f14f8
  //state:线程状态 schedstat:CPU调度时间统计  utm/stm:用户态/内核态的CPU时间(单位jiffies)    core:该线程最后运动所在核 HZ:时钟频率
  | state=? schedstat=( 0 0 0 ) utm=0 stm=0 core=0 HZ=100
  //stack:线程栈的地址区间  stackSize:栈的大小
  | stack=0x7fd8b58000-0x7fd8b5a000 stackSize=8192KB
  //线程所持有的当前虚拟机的multex名称,及持有方式:shared held:共享锁;exclusive held:独占锁
  | held mutexes= "mutator lock"(shared held)
  //说明主线程在等待下条消息进入消息队列
  at android.os.MessageQueue.nativePollOnce(Native method)
  at android.os.MessageQueue.next(MessageQueue.java:374)
  at android.os.Looper.loop(Looper.java:185)
  at android.app.ActivityThread.main(ActivityThread.java:9032)
  at java.lang.reflect.Method.invoke(Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:614)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1129)

main线程的状态是cpp代码中定义的状态

状态 说明
ZOMBIE 线程死亡,终止运行
RUNNABLE/RUNNING 线程可运行或正在运行
TIME_WAIT 执行了带有超时参数的wait、sleep或join函数
MONITOR 线程阻塞,等待获取对象锁
WAIT 执行了无超时参数的wait函数
INITIALIZING 新建,正在初始化,为其分配资源
STARTING 新建,正在启动
NATIVE 正在执行JNI本地函数
VMWAIT 正在等待VM资源
SUSPENDED 线程暂停,通常是由于GC或debug被暂停

案例整理中...

上一篇下一篇

猜你喜欢

热点阅读