Android:ANR问题是什么和如何避免

39 篇文章 0 订阅
33 篇文章 1 订阅


前言

ANR问题在我们Android开发中经常会遇到,但是如何清晰地把ANR问题的定义表述出来和详述ANR问题如何解决则是一个需要整理的过程,本节就针对ANR问题进行整理

一、ANR是什么?

**ANR(Application Not responding)**是指应用程序未响应,Android系统对于一些事件需要在一定的时间范围内完成,如果超过预定时间能未能得到有效响应或者响应时间过长,都会造成ANR。ANR由消息处理机制保证,Android在系统层实现了一套精密的机制来发现ANR,核心原理是消息调度和超时处理

ANR的实质是主线程失去在限定的时间内处理完一些最常见的操作(启动服务、处理广播、处理输入)的能力,前置条件有新的操作需要主线程进行响应,而造成主线程失去响应能力的往往是一些主线程中的耗时操作,譬如密集CPU运算、大量IO、复杂界面布局,都会降低应用程序的响应能力。

二、ANR时间规定

1.Service Timeout

  • 对于前台服务,定义的超时时间为20秒
  • 对于后台服务,定义的超时时间为200秒

2.BroadcastQueue Timeout

  • 对于前台广播,定义的超时时间为10秒
  • 对于后台广播,定义的超时时间为60秒

3.ContentProvider Timeout

  • 超时时间为10秒

4.InputDispatching Timeout

  • 输入事件分发超时5s,包括按键和触摸事件

注意事项:Input的超时机制与其他机制不同,对于input来说即使某次事件执行事件超过timeout时长,只要用户后续没有再生成输入事件,则不会触发ANR

三、ANR场景分析

解决ANR一直是Android 开发者需要掌握的重要技巧,一般从三个方面着手。

开发阶段:通过工具检查各个方法的耗时,卡顿情况,发现一处修改一处。

线上阶段:这个阶段主要依靠监控工具发现ANR并上报,比如matrix。

分析阶段:如果线上用户发生ANR,并且你获取了一份日志,这就涉及了本文要分享的内容——ANR日志分析技巧。

InputEvent Timeout

a.InputDispatcher发送key事件给 对应的进程的 Focused Window,对应的window不存在、处于暂停态、或通道(input channel)占满、通道未注册、通道异常、或5s内没有处理完一个事件,就会发生ANR ​
b.InputDispatcher发送MotionEvent事件有个例外之处:当对应Touched Window的 input waitQueue中有超过0.5s的事件,inputDispatcher会暂停该事件,并等待5s,如果仍旧没有收到window的‘finish’事件,则触发ANR
​ c.下一个事件到达,发现有一个超时事件才会触发ANR

BroadcastReceiver Timeout

a.静态注册的广播和有序广播会ANR,动态注册的非有序广播并不会ANR ​
b.广播发送时,会判断该进程是否存在,不存在则创建,创建进程的耗时也算在超时时间里 ​
c.只有当进程存在前台显示的Activity才会弹出ANR对话框,否则会直接杀掉当前进程 ​
d.当onReceive执行超过阈值(前台15s,后台60s),将产生ANR ​
e.如何发送前台广播:Intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)

Service Timeout

a.Service的以下方法都会触发ANR:onCreate(),onStartCommand(), onStart(), onBind(), onRebind(), onTaskRemoved(), onUnbind(), onDestroy(). ​
b.前台Service超时时间为20s,后台Service超时时间为200s ​
c.如何区分前台、后台执行————当前APP处于用户态,此时执行的Service则为前台执行。 ​
d.用户态:有前台activity、有前台广播在执行、有foreground service执行

ContentProvider 类型

a.ContentProvider创建发布超时并不会ANR ​
b.使用ContentProviderclient来访问ContentProverder可以自主选择触发ANR,超时时间自己定
client.setDetectNotResponding(PROVIDER_ANR_TIMEOUT);

四.导致ANR的原因

导致ANR的原因大致分为两类,一种是应用层导致ANR,一种是系统导致ANR。

应用层导致ANR

a. 函数阻塞:如死循环、主线程IO、处理大数据 ​
b. 锁出错:主线程等待子线程的锁 ​
c.内存紧张:系统分配给一个应用的内存是有上限的,长期处于内存紧张,会导致频繁内存交换,进而导致应用的一些操作超时

系统导致ANR

a. CPU被抢占:一般来说,前台在玩游戏,可能会导致你的后台广播被抢占CPU
​ b.系统服务无法及时响应:比如获取系统联系人等,系统的服务都是Binder机制,服务能力也是有限的,有可能系统服务长时间不响应导致ANR ​
c. 其他应用占用的大量内存

应用层导致的ANR往往在开发阶段便可以通过相关日志定位语句分析得出,但系统导致的ANR往往需要通过分析日志观察CPU使用情况

五.ANR日志分析

发生ANR时,如果是开发阶段,可以直接通过编译器打印日志收集进行观察,也可以通过观察trace文件得到我们想要的信息

系统产生的anr日志文件(手机的**/data/anr** 目录下,文件名称可能各厂商不一样,业内大多称呼为trace文件),内含如下几项重要信息。

CPU负载分析

来看一段ANR日志中关于CPU的分析

Load: 2.62 / 2.55 / 2.25
CPU usage from 0ms to 1987ms later (2020-03-10 08:31:55.169 to 2020-03-10 08:32:17.156):
  41% 2080/system_server: 28% user + 12% kernel / faults: 76445 minor 180 major
  26% 9378/com.xiaomi.store: 20% user + 6.8% kernel / faults: 68408 minor 68 major
........省略N行.....
66% TOTAL: 20% user + 15% kernel + 28% iowait + 0.7% irq + 0.7% softirq

第一行:1、5、15 分钟内正在使用和等待使用CPU 的活动进程的平均数
第二行:表明负载信息抓取在ANR发生之后的0~1987ms。同时也指明了ANR的时间点:2020-03-10 08:31:55.169
中间部分:各个进程占用的CPU的详细情况
最后一行:各个进程合计占用的CPU信息。
在这里插入图片描述

对最后一行分析如下:
1.iowait占比非常高,说明输入输出流堵塞, 一般这种情况发生在读写操作、网络操作
2.user占比非常高,说明在进行大量的计算,导致Ui主线程分配不到时间片,从而导致ANR的产生
3.kernel占比非常高,说明系统本身内核层就存在严重的Bug
4.softirq为软中断,irq为硬中断

内存信息

Total number of allocations 476778  进程创建到现在一共创建了多少对象
​
Total bytes allocated 52MB 进程创建到现在一共申请了多少内存
​
Total bytes freed 52MB   进程创建到现在一共释放了多少内存
​
Free memory 777KB    不扩展堆的情况下可用的内存
​
Free memory until GC 777KB  GC前的可用内存
​
Free memory until OOME 383MB  OOM之前的可用内存
​
Total memory 当前总内存(已用+可用)
​
Max memory 384MB  进程最多能申请的内存

这里来看一段内存使用信息状况
**Free memory until OOME **的值很小的时候,已经处于内存紧张状态。应用可能是占用了过多内存。

堆栈消息

观察堆栈消息,主要是分析堆栈中各线程的状态,

main线程处于 BLOCK、WAITING、TIMEWAITING状态,那基本上是函数阻塞导致ANR;

如果main线程无异常,则应该排查CPU负载和内存环境。

  • 1
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值