如何分析ANR问题?

1 为什么会产生ANR

在Android里, App的响应能力是由Activity Manager和Window Manager系统服务来监控的. 通常在如下三种情况下会弹出ANR对话框:

1:5s内无法响应用户输入事件(例如键盘输入, 触摸屏幕等)
2:BroadcastReceiver在10s内无法结束
3:ServiceTimeout(20s) --小概率类型,Service在特定的时间内无法处理完成

造成以上两种情况的首要原因就是在主线程(UI线程)里面做了太多的阻塞耗时操作, 例如文件读写, 数据库读写, 网络查询等.

2 ANR分析

2.1 获取ANR产生的trace文件

ANR产生时, 系统会生成一个traces.txt的文件放在/data/anr/下. 可以通过[adb]命令将其导出到本地:

$adb pull data/anr/traces.txt .

本例中问题出现在MainActivity.java 27行,因为这里调用了Thread.sleep方法。

----- pid 30307 at 2018-09-06 14:51:14 -----
Cmd line: com.example.android

JNI: CheckJNI is off; workarounds are off; pins=0; globals=272

DALVIK THREADS:
(mutexes: tll=0 tsl=0 tscl=0 ghl=0)

"main" prio=5 tid=1 TIMED_WAIT
  | group="main" sCount=1 dsCount=0 obj=0x416eaf18 self=0x416d8650
  | sysTid=30307 nice=0 sched=0/0 cgrp=apps handle=1074565528
  | state=S schedstat=( 0 0 0 ) utm=5 stm=4 core=3
  | stack=0x7fdc4ca000-0x7fdc4cc000 stackSize=8MB
  | held mutexes=
  at java.lang.VMThread.sleep(Native Method)
  at java.lang.Thread.sleep(Thread.java:1044)
  at java.lang.Thread.sleep(Thread.java:1026)
  at com.example.android.MainActivity$1.run(MainActivity.java:27)
  at android.app.Activity.runOnUiThread(Activity.java:4794)
  at com.example.android.MainActivity.onResume(MainActivity.java:33)
  at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1282)
  at android.app.Activity.performResume(Activity.java:5405)

从第一行开始我们来按每一行解析其所代表的含义。

1,代表 PID at time
2,Cmd line: process name
3,固定头,指明下面都是当前运行的dvm thread ,“DALVIK THREADS:” 及所包含的线程数
4,"main" prio=5 tid=1 Native
分别代表thread name, java thread Priority, DVM thread id, DVM thread status
"main" :main thread -> activity thread
prio :java thread priority default is 5, (正常区域是1-10)
tid:是DVM thread id, 不是 linux thread id(下一行的sysTid才是)
Native:DVM thread Status 正常有这些状态(ZOMBIE, RUNNABLE, TIMED_WAIT, MONITOR, WAIT, INITALIZING,STARTING, NATIVE, VMWAIT, SUSPENDED,UNKNOWN)
5,group="main" sCount=1 dsCount=0 obj=0x416eaf18 self=0x416d8650
代表 DVM thread status。
group:是线程所处的线程组 default is “main”
sCount: 线程被正常挂起的次数 1 (thread suspend count)
dsCount: 线程因调试而挂起次数 0 (thread dbg suspend count)
obj: 当前线程所关联的java线程对象 0x75720fb8 (thread obj address)
Sef: 该线程本身的地址 0x7f7e8af800 (thread point address)
6,sysTid=30307 nice=0 sched=0/0 cgrp=apps handle=1074565528
代表Linux thread status显示线程调度信息
sysTId: linux系统下得本地线程id linux thread tid
Nice:线程的调度有优先级 linux thread nice value
cgrp: 优先组属 c group
sched: 调度策略 cgroup policy/gourp id
handle: 处理函数地址 handle address
7,state=S schedstat=( 0 0 0 ) utm=5 stm=4 core=3
代表CPU Sched stat 显示更多该线程当前上下文
State:调度状态 process/thread state (正常有 "R (running)", "S (sleeping)", "D (disk sleep)", "T (stopped)", "t (tracing stop)", "Z (zombie)", "X (dead)", "x (dead)", "K (wakekill)", "W (waking)",),通常一般的Process 处于的状态都是S (sleeping), 而如果一旦发现处于如D (disk sleep), T (stopped), Z (zombie) 等就要认真审查.
Schedstat (Run CPU Clock/ns, Wait CPU Clock/ns, Slice times) 该线程运行信息
utm: utime, user space time 线程用户态下使用的时间值(单位是jiffies)
stm: stime, kernel space time 内核态下得调度时间值
core: now running in cpu. 最后运行改线程的cup标识
8,stack=0x7f7dc93000-0x7f7dc95000 stackSize=1020KB
代表堆栈地址区域及size
9,held mutexes=
代表是否被锁住,正常有四个属性(mutexes: tll=0 tsl=0 tscl=0 ghl=0),0表示unlock,其它值都代表被lock,
tll: thread List Lock,
tsl: thread Suspend Lock,
tscl: thread Suspend Count Lock
ghl: gc Heap Lock
10,剩余的就是一些 Call Stack

2.2 CPU负荷和CPU使用率

//CPU前一分钟、五分钟、十五分钟的CPU平均负载, 
//CPU平均负载可以理解为一段时间内正在使用和等待使用CPU的活动进程的平均数量。
    Load: 5.16 / 9.69 / 30.66      
//ago,表示ANR发生之前的一段时间内的CPU使用率,并不是某一时刻的值
    CPU usage from 34388ms to -1ms ago:
    4.1% 32614/com.qihoo.browser: 2.5% user + 1.6% kernel / faults: 465 minor 1 major
    3% 379/adbd: 0.2% user + 2.8% kernel / faults: 1653 minor
    2.6% 743/system_server: 1.8% user + 0.7% kernel / faults: 689 minor
    2.5% 2326/com.qihoo.daemon: 2.2% user + 0.2% kernel / faults: 601 minor
    2.4% 1009/RX_Thread: 0% user + 2.4% kernel
    2% 280/surfaceflinger: 1.2% user + 0.8% kernel / faults: 1361 minor
    1.8% 2675/com.lbe.security:service: 1.7% user + 0.1% kernel / faults: 749 minor
    .......
    +0% 3682/migration/1: 0% user + 0% kernel
    +0% 3683/kworker/1:0: 0% user + 0% kernel
    +0% 3684/ksoftirqd/1: 0% user + 0% kernel
    9.7% TOTAL: 4.8% user + 4.2% kernel + 0.3% iowait + 0.3% softirq
//later,表示ANR发生之后
    CPU usage from 1656ms to 2187ms later:
    8.7% 743/system_server: 0% user + 8.7% kernel / faults: 4 minor
    7% 943/InputDispatcher: 0% user + 7% kernel
    1.7% 1199/Binder_6: 0% user + 1.7% kernel
    5.2% 379/adbd: 0% user + 5.2% kernel / faults: 27 minor
    3.5% 379/adbd: 0% user + 3.5% kernel
    1.7% 1009/RX_Thread: 0% user + 1.7% kernel
    1.7% 1768/mpdecision: 0% user + 1.7% kernel
    1.7% 1784/mpdecision: 0% user + 1.7% kernel
    1.2% 6883/kworker/u:37: 0% user + 1.2% kernel
    1.3% 29165/kworker/0:2: 0% user + 1.3% kernel
    2.3% TOTAL: 0.1% user + 0.3% kernel + 1.8% iowait

如果说某个进程在ANR发生时CPU使用率出现很高的情况,那么就可以知道这个进程在做非常消耗CPU的事情,一般这种情况下这个进程就是ANR进程,而消耗CPU的这个事情往往就是导致ANR的根源。

2.3 内存原因

内存原因有可能会导致ANR, 例如如果由于内存泄露, App可使用内存所剩无几.
// 以下trace信息来自网络, 用来做个示例

Cmdline: android.process.acore

DALVIK THREADS:
"main"prio=5 tid=3 VMWAIT
|group="main" sCount=1 dsCount=0 s=N obj=0x40026240self=0xbda8
| sysTid=1815 nice=0 sched=0/0 cgrp=unknownhandle=-1344001376
atdalvik.system.VMRuntime.trackExternalAllocation(NativeMethod)
atandroid.graphics.Bitmap.nativeCreate(Native Method)
atandroid.graphics.Bitmap.createBitmap(Bitmap.java:468)
atandroid.view.View.buildDrawingCache(View.java:6324)
atandroid.view.View.getDrawingCache(View.java:6178)

...

MEMINFO in pid 1360 [android.process.acore] **
native dalvik other total
size: 17036 23111 N/A 40147
allocated: 16484 20675 N/A 37159
free: 296 2436 N/A 2732

可以看到free的内存已所剩无几.

3 ANR的处理

三种不同的情况, 一般的处理情况如下
1.主线程阻塞

开辟单独的子线程来处理耗时阻塞事务.

2.CPU满负荷, I/O阻塞

I/O阻塞一般来说就是文件读写或数据库操作执行在主线程了, 也可以通过开辟子线程的方式异步执行.

3.内存不够用

增大VM内存, 使用largeHeap属性, 排查内存泄露等.

感谢
1.ANR分析思路简析-https://blog.csdn.net/sinat_34157462/article/details/78651870
2.Android应用ANR分析-https://www.jianshu.com/p/30c1a5ad63a3

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • ANR问题,相信是每位开发日常都会遇到的问题,对于这类问题的分析,按照官方的推荐,或网络博客的总结思路能解决一定的...
    tiger桂阅读 17,886评论 5 28
  • 进程和线程 进程 所有运行中的任务通常对应一个进程,当一个程序进入内存运行时,即变成一个进程.进程是处于运行过程中...
    胜浩_ae28阅读 5,089评论 0 23
  • 本文是我自己在秋招复习时的读书笔记,整理的知识点,也是为了防止忘记,尊重劳动成果,转载注明出处哦!如果你也喜欢,那...
    波波波先森阅读 11,244评论 4 56
  • 就算栽下一棵菩提,诚心膜拜又如何,装装样子,掩掩性子,人总有七情六欲的。——夏枫 翌日一早,本是疲倦的我却早早起了...
    与无阅读 573评论 2 1
  • 短短五天。我所在的原本安安静静的城市突然进入了紧急急迫的状态。 6月29号,突然接到通知,30号和1号要去滁州小岗...
    海北sunshine阅读 283评论 0 0