Android ANR分析

前言

  ANR(Application Not Responding)即应用无响应,在Android系统中,应用发生的ANR由以下几种类型:

类型 说明
KeyDispatchTimeout 最常见的ANR类型是对输入事件5秒内无响应,比如按键或者触摸事件在此时间内无响应。
BroadcastTimeout BroadcastTimeout是在指定时间内(原生系统默认是10s)内无法处理完成,并且没有结束执行onReceive。
ServiceTimeout 这种类型在Android应用中出现的概率很小,是指Service在特定的时间(原生系统是20s)内无法处理完成。

  引起ANR的根本原因总体来说有以下两种:

  • 应用程序本身逻辑有缺陷,或者在某些异常场景触发了此缺陷,如主线程堵塞、死锁循环等导致的。
  • 由于Android设备其他进程的CPU占用搞,导致当前应用进程无法抢占到CPU时间片。

ANR文件介绍

  在Android系统中,如果发生ANR,Logcat会产生对应的日志和一个trace文件,分析ANR的原因主要是分析这两个信息。trace文件在Android中的路径为/data/anr/traces.txt,可以使用adb来获取,adb pull /data/anr/traces.txt
  Logcat文件信息信息:

信息 说明
ANR IN 发生AND的具体类。
PID 发生ANR的进程,系统在此时会产生trace文件,当前的时间点也是发生ANR的具体时间,以及生成trace文件的时间。
Reason 当前ANR的类型以及导致ANR的原因。
CPU usage CPU的使用情况。

  从Logcat中除了能看出在哪个类发生了ANR以及ANR的类型,具体的原因主要还是要看CPU的使用情况,如果CPU使用量很少,说明主线程可能堵塞,如果IOwait很高,说明ANR有可能是由于主线程进行耗时I/O操作造成的。

ANR文件分析

  使用如下代码,模拟ANR:

public void onANR(View view) {
    Toast.makeText(this, "开始ANR模拟", Toast.LENGTH_SHORT).show();
    try {
        Thread.sleep(1000000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

  模拟结果如下:(注意:时间有点长,请耐心等待O(∩_∩)O)
这里写图片描述

  使用adb pull /data/anr/提取发生ANR之后生成的traces文件。

这里写图片描述

  使用Android Studio上提供的一个分析traces文件的工具:Analyze Stacktrace。Analyze Stacktrace可以更加直观地分析导致ANR的工具。
  Analyze Stacktrace使用方法:

  1. 在Android Studio的工具栏中,选择Analyze->Analyze Stackstrace,打开Analyze Stackstrace工具窗口。
  2. 将traces.txt中的内容复制到窗口,单击Normalize按钮,生成Thread Dump列表,左边为所有线程列表,右边为选中线程的具体信息。

这里写图片描述

这里写图片描述

  导致AND的信息为:

"main" prio=5 tid=1 Sleeping  | group="main" sCount=1 dsCount=0 obj=0x74239fa8 self=0x7f3e24897000  | sysTid=29044 nice=0 cgrp=apps sched=0/0 handle=0x7f3e27ba86a0  | state=S schedstat=( 0 0 0 ) utm=48 stm=43 core=0 HZ=100  | stack=0x7fff22dd1000-0x7fff22dd3000 stackSize=8MB  | held mutexes=
  at java.lang.Thread.sleep!(Native method)
  - sleeping on <0x1b893c4d> (a java.lang.Object)
  at java.lang.Thread.sleep(Thread.java:1031)
  - locked <0x1b893c4d> (a java.lang.Object)
  at java.lang.Thread.sleep(Thread.java:985)
  at link_work.myapplication.MainActivity.onANR(MainActivity.java:147)
  at java.lang.reflect.Method.invoke!(Native method)
  at java.lang.reflect.Method.invoke(Method.java:372)
  at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
  at android.view.View.performClick(View.java:4756)
  at android.view.View$PerformClick.run(View.java:19749)
  at android.os.Handler.handleCallback(Handler.java:739)
  at android.os.Handler.dispatchMessage(Handler.java:95)
  at android.os.Looper.loop(Looper.java:135)
  at android.app.ActivityThread.main(ActivityThread.java:5221)
  at java.lang.reflect.Method.invoke!(Native method)
  at java.lang.reflect.Method.invoke(Method.java:372)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

  从上面的信息中at link_work.myapplication.MainActivity.onANR(MainActivity.java:147)可以看出问题发生在这里。主要原因是因为线程休眠的时间太长了,导致了ANR。

附录

  • 《Android应用性能优化最佳实践》
    • 罗彧成
本站公众号
   欢迎关注本站公众号,获取更多程序园信息
开发小院