美文网首页Android开发之散记开发
性能优化(六):ANR问题分析

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

作者: w达不溜w | 来源:发表于2022-02-18 11:22 被阅读0次

    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原因

    • 应用层导致ANR

      1. 主线程函数阻塞:如死循环、主线程IO等
      2. 多线程操作的死锁,主线程被block
      3. 内存紧张:系统分配给一个应用内存是有限的,长期处于内存紧张会导致内存交换,进而导致一些操作超时
    • 系统导致ANR

      1. CPU被抢占

      2. 系统服务无法及时响应:系统服务都是Binder机制(16个线程),服务能力也是有限的,service的连接达到上限无法和系统服务通信

      3. 其它应用占用大量内存

    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被暂停

    案例整理中...

    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/ydtylrtx.html