ANR基本分析

1.ANR介绍。

ANR全名Application Not Responding, 也就是"应用无响应". 当操作在一段时间内系统无法处理时, 系统层面会弹出上图那样的ANR对话框.

 

  • KeyDispatchTimeout 5s内无法响应用户输入事件(例如键盘输入, 触摸屏幕等).
  • BroadcastReceiver在10s/60s内无法结束(前后台广播)..
  • ServiceTimeout(20 seconds) (前台service时间)
  • ContentProvider anr时间由apk自身设定(少见)

 

 

2 。如何避免ANR

知道了ANR产生的原因, 那么想要避免ANR, 也就很简单了, 就一条规则:

不要在主线程(UI线程)里面做繁重的操作.

这里面实际上涉及到两个问题:

  1. 哪些地方是运行在主线程的?
  2. 不在主线程做, 在哪儿做?

主线程:Activity:onCreate(), onResume(), onDestroy(), onKeyDown(), onClick(),etc AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel,etc Mainthread handler: handleMessage(), **post***(runnable r), etc Other

 

耗时的工作(比如数据库操作,I/O,连接网络或者别的有 可能阻碍 UI 线程的操作)把它放入单独的线程处理. 比如打开wifi(因为跨进程操作,有可能wifiserver那边处理超时) 读写文件(操作是个iowait负载较大的行为,很容易anr) 查询语句(在数据库内容暴增之后,出现严重的性能问题,产生anr) SharedPreferences 的commit操作,本身是个等待操作,在我们activity退出时,有时保存当前状态,方便恢复,会使用commit,如果我们也有一个此时在操作,因为这个操作是有个锁,引起anr list的排序。(算法的质量,以及当列表数目激增后,是否能快速算完,是个耗时操作,会产生anr) bitmap的运算,(旋转,特效处理等) ThreadPoolExecutor 线程池,当我们从这里获取一个线程时候,如果此时所有线程都被使用,就只能迫使等待,此时会出现anr

sleep操作不会释放锁,也注意

3.分析步骤

1.找到ANR 位置

需要文件bugreport(trace信息 binderinfo信息 )  event log(am_anr) device log(main system log) kernel log(lowmemorykiller等等)

搜索关键字"am_anr"确认类型之类,搜索"ANR in"找到event log位置

2.看cpu信息,是否有特别高的进程,整体占用是否高,是否io高引起

进程高:可以通过搜索进程pid看在干什么,也可以通过trace文件看在做什么,通过pid tid

3.查看anr之前处于什么状态,有没有异常之类的

可以搜索event log anr的"pid tid"来看主线程在干什么,最后在做什么,有没有线索

device log搜索 pid pid看是否有异常情况

检测log看发生anr之前是否有异常情况,比如native crash ,out of memory之类

4.AMS在AppError.java中dump anr信息时,假如message history log那么就可以看到主线程卡了多久,卡在什么message(实现可以通过looper.java里实现)

5.查看trace

通过trace文件或者anr_history.txt,搜索cmd line: xxx或者pid  xxx来看是否能够对应时间,由于anr是ui线程卡,因此只需要看主线程(main)trace

4.可能原因

系统性能影响:

cpu usage高(比如kspxx名字进程,可能就与内存不足有关,usb进程那么可能是usb不兼容之类) 

low memory*(通过搜索kernel log对应时间点,lowmemorykiller关键字,一般kill adj<=2,那么系统就处于严重低内存状态,可能出现crash anr 系统缓慢 重启等问题)

主线程操作:IO文件访问  网络访问 thread.join  sleep SharedPreferences.commit等操作

5.trace log pattern(非常重要)

http://blog.youkuaiyun.com/ruingman/article/details/53118202
具体图案引用上述网站

//代表此线程是从另一个线程binder过来的,可以在binderinfo搜索30228:1612(pid:tid)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112)  
at android.os.Binder.execTransact(Binder.java:453)


//看到BinderProxy.transactNative + IPCThreadState表示此线程binder了另一个线程,分析时需要看binderinfo transaction确认是那个线程问题
native: #05 pc 000198dd  /system/lib/libbinder.so (_ZN7android7BBinder8transactEjRKNS_6ParcelEPS1_j+60)
native: #06 pc 0001ec25  /system/lib/libbinder.so (_ZN7android14IPCThreadState14executeCommandEi+584)
native: #07 pc 0001ef73  /system/lib/libbinder.so (_ZN7android14IPCThreadState15waitForResponseEPNS_6ParcelEPi+262)
native: #08 pc 0001f049  /system/lib/libbinder.so (_ZN7android14IPCThreadState8transactEijRKNS_6ParcelEPS1_j+124)
native: #09 pc 00019fe3  /system/lib/libbinder.so (_ZN7android8BpBinder8transactEjRKNS_6ParcelEPS1_j+30)
native: #10 pc 0008a035  /system/lib/libandroid_runtime.so (???)
native: #11 pc 00d78919  /data/dalvik-cache/arm/system@framework@boot.oat (Java_android_os_BinderProxy_transactNative__ILandroid_os_Parcel_2Landroid_os_Parcel_2I+140)
at android.os.BinderProxy.transactNative(Native method)
at android.os.BinderProxy.transact(Binder.java:505)

//binderinfo信息(一般在anr_history bugreport binderinfo.txt)此处表示pid 30228 tid1612的线程binder到15625:15635(pid15625 tid15635)
outgoing transaction 623807: edbbfa40 from 30228:1612 to 15625:15635 code 1 flags 10 pri 10 r1 node 222269 size 740:4 data fb600404

//下面这个15625:0表示pid 30228 tid1612的线程binder到15625,但是失败了,一般是因为15625 16个binder被占完了(system_server 32个binder),此时就需要通过trace看15625是被什么占的
outgoing transaction 623807: edbbfa40 from 30228:1612 to 15625:0 code 1 flags 10 pri 

//假如System_server中Block在此log表示,system_server 32binder沾满,没有可用binder
at android.os.Binder.blockUntilThreadAvailable(Native method)

//表示等锁0x0eeb54f1,这个锁是被tid=40持有()
  at com.android.server.MountService.getVolumeList(MountService.java:2759)
  - waiting to lock <0x0eeb54f1> (a java.lang.Object) held by thread 40

//"main"表示主线程 tid=1表示trace中的线程号,主线程为1  sysTid=22831表示系统tid,就是log中的线程号 utm=22 stm=22表示用户空间时间,可kernel空间时间,为22*10ms
 "main" prio=5 tid=1 Native
| group="main" sCount=1 dsCount=0 obj=0x73ee6470 self=0xb4d76500
| sysTid=22831 nice=0 cgrp=default sched=0/0 handle=0xb6f4bc00
| state=S schedstat=( 0 0 0 ) utm=22 stm=22 core=0 HZ=100

 

推荐这个博主对于Stability写的比较细:

https://www.jianshu.com/p/18f16aba79dd

 

<think>好的,我现在需要帮助用户了解Android ANR问题的原因和解决方法。首先,我要回忆一下ANR基本概念。ANR是当应用主线程被阻塞超过一定时间时,系统弹出的无响应提示。常见情况有主线程进行耗时操作,比如网络请求、数据库操作或者复杂的计算等。 根据用户提供的引用内容,我需要整合各个来源的信息。引用[1]提到trace.txt文件的结构和获取方法,引用[3]解释了ANR的触发机制,引用[4]则介绍了通过Logcat获取日志的方法。还有引用[2]中的案例集,可能涉及实际问题的分析步骤。 接下来,我需要组织回答结构。首先解释ANR的定义,然后详细说明主要原因,如主线程阻塞、锁竞争、过度布局等。接着给出分析步骤,比如获取trace.txt、分析堆栈信息、使用Android Studio工具等。解决方案部分要针对每个原因提出具体的优化方法,如使用子线程、减少布局复杂度、优化数据库查询等。 需要注意引用标记的正确使用,比如在提到trace.txt时添加[^1],分析ANR日志时引用[^4]。同时,确保使用正确的中文表达,避免技术术语错误。还要检查LaTeX格式是否符合要求,虽然这个问题可能不涉及数学公式,但如果有变量或代码块,需要正确应用格式。 用户可能还想知道如何预防ANR,或者在实际开发中如何调试。因此,在相关问题部分,可以列出ANR的监控工具、预防措施、常见案例等,帮助用户进一步学习。 最后,验证信息是否准确,比如adb命令是否正确,分析步骤是否合理,解决方案是否可行。确保引用来源与内容对应,没有混淆。例如,trace.txt的获取方法来自引用[1],而Logcat的使用来自引用[4]。</think>### Android ANR问题的原因及解决方法 #### 一、ANR的定义 当应用主线程(UI线程)因耗时操作阻塞超过系统阈值时,Android系统会触发 **Application Not Responding**(ANR)[^3]。默认阈值: - **输入事件响应**:5秒 - **广播接收**:10秒 - **服务处理**:20秒 --- #### 二、主要原因分析 1. **主线程阻塞** - 直接执行网络请求、数据库操作或复杂计算(如$O(n^2)$算法) - 示例:在主线程中调用`Thread.sleep(10000)` 2. **锁竞争** - 主线程与其他线程争夺同步锁,导致死锁或长时间等待 3. **过度布局计算** - 复杂的`View`层级或未优化的`RecyclerView`布局 4. **低效的I/O操作** - 大文件读写或未索引的数据库查询 --- #### 三、分析步骤(引用trace.txt与日志) 1. **获取ANR日志** - 通过ADB提取: ```bash adb pull /data/anr/traces.txt ``` - 在Android Studio的Logcat中过滤关键字`ANR`和`ActivityManager`[^1] 2. **分析堆栈信息** - 查看主线程状态:定位阻塞位置(如`wait()`, `lock()`或耗时函数) - 示例堆栈片段: ``` "main" prio=5 tid=1 Native | group="main" sCount=1 dsCount=0 flags=1 obj=0x74e45e30 | sysTid=1234 nice=-10 cgrp=default sched=0/0 handle=0x7f8e5a4000 | state=S schedstat=( 12345678 9876543 123 ) utm=12 stm=5 core=1 at java.lang.Object.wait(Native Method) at com.example.MyClass.blockingMethod(MyClass.java:20) ``` 3. **使用工具辅助** - Android Profiler检查CPU/内存占用 - StrictMode检测主线程I/O操作 --- #### 四、解决方案 | 问题类型 | 解决方法 | |-------------------|--------------------------------------------------------------------------| | 主线程耗时操作 | 使用`AsyncTask`、`Kotlin协程`或`RxJava`将任务移至子线程 | | 布局性能问题 | 通过`Layout Inspector`优化视图层级,使用`ConstraintLayout`减少嵌套 | | 数据库低效查询 | 添加索引,改用`Room`库并启用`@Transaction`批处理 | | 锁竞争 | 使用`ReentrantLock`替代`synchronized`,设置超时时间(如`tryLock(100ms)`)| --- #### 五、预防措施 1. **代码规范** - 使用`@WorkerThread`注解明确线程类型 - 通过`Handler.postDelayed()`延迟非紧急任务 2. **监控工具** - 集成华为AGC性能管理服务实时监测ANR率[^2] - 启用`ANRWatchDog`库主动捕获潜在ANR ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值