Android稳定性专题之ANR
来源:互联网 发布:贵州软件评测机构 编辑:程序博客网 时间:2024/05/16 09:59
1. ANR问题
ANR,应用程序无响应,是Android应用程序稳定性问题的另一类重要问题。
1.1 ANR是什么
首先,我们来看一下Android官网上对于ANR的说明,https://developer.android.com/training/articles/perf-anr.html
在Android中,程序的响应性是由Activity Manager与Window Manager系统服务来负责监控的。当系统监测到下面的条件之一时会显示ANR的对话框:
- 对输入事件(例如硬件点击或者屏幕触摸事件),5秒内都无响应。
- BroadReceiver不能够在10秒内结束接收到任务
Android官网上列出的文章较老,再多补充一下触发条件
1.2 ANR的触发原因
简单的说,就是主线程(UI线程)被耗时操作阻塞,无法及时完成工作,导致了ANR。
深入了解Android的基础组件,会发现Activity,Service,BroadcastReceiver,ContentProvider等基本的生存周期回调函数是运行在主线程中的。包括UI控件的各类事件响应回调函数也是运行在主线程中的。那么,在这些函数中,如果发生了阻塞,就会触发ANR。具体有哪些问题呢,这里举一些例子:
- 主线程中执行了耗时操作,比如:
- 网络访问
- 数据库读写
- 文件读写
- 复杂的耗时算法
- wait()、sleep()、join()、等线程操作
- 其他线程或进程占用了CPU资源,导致主线程无法获取CPU资源
- 多线程发生死锁,主线程一直无法获取锁,造成阻塞
2. 如何避免ANR问题
根据1.2节中的分析,只要能够消除造成主线程阻塞的原因,就可以避免ANR的发生。
首先,做好架构设计。UI展示,与业务逻辑有效分离,比如采用MVC模式。
其次,各种耗时操作都放在子线程中处理,比如,网络访问,数据库操作,文件读写,其他各种IO,图像处理,耗时算法等等。
- 技术手段可以选择AsyncTask,或者自己编写Thread + Handler模型,线程池等技术手段。
- UI交互上,在等待耗时操作的时候,引入更多的提示,比如进度条,提示框等。
也可以通过修改页面流程让交互更流畅,比如启动时增加一个闪屏,为应用的初始化争取到足够的加载时间。
再次,优化多线程机制,sleep(),wait(),join()放到子线程中处理,可以在主线程中增加回调,比如在子线程中持有主线程中的handler,采用handler-message机制,可以回调触发主线程任务。
另外,避免主线程中发生死锁。
3. 发生了ANR,如何分析解决
理想很丰满,现实很骨感。种种原因,特别是在压力测试中,开发人员还是要面对各种各样的ANR问题。
那么,对于ANR问题,我们该如何分析呢。
3.1 ANR日志的生成
当ANR发生时,Android系统中的AMS(ActivityManagerService)会进行处理。ANR的日志会输出到 /data/anr/traces.txt 文件中。
这个过程会清空/data/anr/traces.txt的老文件, 那么原来之前的traces信息一般地会先输出到 /data/system/dropbox 实际工作中,存在trace文件丢失的情况。
关注细节的话,这里可以多提一下,对于Java和Native,系统在ANR的处理过程中采用不同的策略。
Java层的处理
所有的Java进程都运行在Java虚拟机上,当应用发生ANR时,其最终的一个环节是向目标进程通过kill -3,发送信号SIGNAL_QUIT。Android进程收到SIGQUIT时,虚拟机会捕获这个信号,并输出相应的traces信息,保存到 /data/anr/traces.txt 中。
Native层的处理
Native进程在发生ANR时,debuggerd服务接收到系统发来的 DEBUGGER_ACTION_DUMP_BACKTRACE 命令,最后通过dump_backtrace()将日志输出到 /data/anr/traces.txt 。
3.2 ANR日志分析
通常ANR问题的分析需要将trace日志和logcat日志结合起来综合分析,才能较好的解决。关于线程状态以及CPU、内存指标在日志中的含义,请参考附录部分的介绍。
总结:
- trace日志和logcat日志要结合起来看。
- trace中的ANR原因,进程号,时间,首个调用栈等信息非常关键。
- logcat日志中一方面查找对应时间的日志,检查应用的行为,检查具体导致SIG:3发出的原因。
- ANR in XXX也是一个关键字,可以在logcat日志中检索。不过这句日志打印的时间通常要比ANR发生的时间晚一些。找到这部分log后,应该顺着向前继续查找ANR发生的日志。
附录
线程状态
查看trace日志时,堆栈信息部分,会显示线程的状态。这里列出Java中定义的线程状态。
Thread.java中定义的状态
Thread.cpp中定义的状态
说明
TERMINATED
ZOMBIE
线程死亡,终止运行
RUNNABLE
RUNNING/RUNNABLE
线程可运行或正在运行
TIMED_WAITING
TIMED_WAIT
执行了带有超时参数的wait、sleep或join函数
BLOCKED
MONITOR
线程阻塞,等待获取对象锁
WAITING
WAIT
执行了无超时参数的wait函数
NEW
INITIALIZING
新建,正在初始化,为其分配资源
NEW
STARTING
新建,正在启动
RUNNABLE
NATIVE
正在执行JNI本地函数
WAITING
VMWAIT
正在等待VM资源
RUNNABLE
SUSPENDED
线程暂停,通常是由于GC或debug被暂停
UNKNOWN
未知状态
日志中关于CPU和内存的关键指标含义
CPU的使用时间:读取 /proc/stat
- user: 用户进程的CPU使用时间
- nice: 降低过优先级进程的CPU使用时间。Linux进程都有优先级,这个优先级可以进行动态调整,譬如进程初始优先级的值设为10,运行时降低为8,那么,修正值-2就定义为nice。 Android将user和nice这两个时间归类成user
- sys: 内核进程的CPU使用时间
- idle: CPU空闲的时间
- wait: CPU等待IO的时间
- hw irq: 硬件中断的时间。如果外设(譬如硬盘)出现故障,需要通过硬件终端通知CPU保存现场,发生上下文切换的时间就是CPU的硬件中断时间
- sw irg: 软件中断的时间。同硬件中断一样,如果软件要求CPU中断,则上下文切换的时间就是CPU的软件中断时间
CPU负载:读取 /proc/loadavg
统计最近1分钟,5分钟,15分钟内,CPU的平均活动进程数。 CPU的负载可以比喻成超市收银员负载,如果有1个人正在买单,有2个人在排队,那么该收银员的负载就是3。 在收银员工作时,不断会有人买单完成,也不断会有人排队,可以在固定的时间间隔内(譬如,每隔5秒)统计一次负载,那么,就可以统计出一段时间内的平均负载。
页错误信息:进程的CPU使用率最后输出的“faults: xxx minor/major”部分表示的是页错误次数,当次数为0时不显示。
- major是指Major Page Fault(主要页错误,简称MPF),内核在读取数据时会先后查找CPU的高速缓存和物理内存,如果找不到会发出一个MPF信息,请求将数据加载到内存。
- minor是指Minor Page Fault(次要页错误,简称MnPF),磁盘数据被加载到内存后,内核再次读取时,会发出一个MnPF信息。 一个文件第一次被读写时会有很多的MPF,被缓存到内存后再次访问MPF就会很少,MnPF反而变多,这是内核为减少效率低下的磁盘I/O操作采用的缓存技术的结果。
- Android稳定性专题之ANR
- Android 系统稳定性之ANR
- Android稳定性专题之开篇
- Android稳定性专题之CRASH
- Android系统稳定性-ANR
- Android 系统稳定性 - ANR
- Android 系统稳定性 - ANR
- Android 系统稳定性---OOM,ANR
- android系统稳定性-ANR(二)
- Android 系统稳定性 - ANR(一)
- Android 系统稳定性 - ANR(二)
- Android 系统稳定性 - ANR(一)
- Android 系统稳定性 - ANR(二)
- Android 系统稳定性 - ANR(三)
- Android 系统稳定性 - ANR(一)
- Android 系统稳定性 - ANR(二)
- Android 系统稳定性 - ANR(三)
- Android 系统稳定性 - ANR(一)
- 区块链笔记分享:
- Eclipse Java 反编译插件安装
- cpu性能 天梯图
- 工具库
- 知识点记录
- Android稳定性专题之ANR
- Ubuntu环境下Android Studio编译5.1系统的APP可以真机运行,但是4.4的体统真机运行会闪退
- rabbitMq生产者角度:消息持久化、事务机制、PublisherConfirm、mandatory
- 理解大型分布式网站你必须知道这些概念
- 设计模式-适配器模式
- 提高mysql千万级大数据SQL查询优化30条经验
- TensorFlow 制作自己的TFRecord数据集
- js 创建csv
- Android Java中将unicode的汉字码转换成utf-8格式的汉字