android anr本质分析及解决办法
来源:互联网 发布:沈阳seo新浪博客 编辑:程序博客网 时间:2024/06/06 07:33
在android开发中经常碰到的一类问题是anr,全称是application not respond,应用程序没有响应,关于这类问题,究其本质是主线程无法响应。而导致主线程无法响应的原因大致如下:
1、主线程请求网络资源,数据库访问或者io访问,这些操作都是耗时操作,主线程处于阻塞状态,如果超时等待,会发生anr
2、cpu处于饥饿状态,无法让主线程运行,导致anr
3、其他进程或者线程占用cpu资源,无法释放资源让该主线程运行,导致anr
4、死锁,即主线程等待的锁正在被其它线程占用,无法释放。
anr问题一般出现在app代码中,systemserver进程中的inputDispatcher线程会一直监听app的响应时间,如果键盘或者触摸事件超时等待5s没有响应,broadcastreceiver超时10s没有响应,或者service超时响应都会发生anr,ActivityManagerService会将anr的直接原因在aplog中打印出来,另外通知kernel往对应进程发送signal 3,将该进程的各个线程的函数堆栈信息打印出来,输出到data/anr/traces.txt中。所以分析anr问题一般主要看的就是aplog和traces.txt。下面主要分析aplog和traces.txt中的log。
Process:com.android.emailActivity:com.android.email/.activity.MessageViewSubject:keyDispatchingTimedOutCPU usage from 2550ms to -2814ms ago:5%187/system_server: 3.5% user + 1.4% kernel / faults: 86 minor 20major4.4% 1134/com.android.email: 0.7% user + 3.7% kernel /faults: 38 minor 19 major4% 372/com.android.eventstream: 0.7%user + 3.3% kernel / faults: 6 minor1.1% 272/com.android.phone:0.9% user + 0.1% kernel / faults: 33 minor0.9%252/com.android.systemui: 0.9% user + 0% kernel0%409/com.android.eventstream.telephonyplugin: 0% user + 0% kernel /faults: 2 minor0.1% 632/com.android.devicemonitor: 0.1% user + 0%kernel100%TOTAL: 6.9% user + 8.2% kernel +84%iowait
这是anr发生后aplog的主要内容,其中会显示cpu平均负载和使用率,实现在代码在activitymanagerservice中。
下面列出几个参考的网站:
anr例子分析:http://blog.csdn.net/fengye810130/article/details/9223063
anr原理分析:http://rayleeya.iteye.com/blog/1955657
死锁分析:http://www.jb51.net/article/38561.htm
http://www.360doc.com/content/13/0222/10/3700464_267198940.shtml
当然,只有理解了多线程的意义才会对anr有较深的理解,下面讲解多线程编程。
先看如下代码,在主线程中起了两个子线程,子线程打印1到50,这里没有用到Runnable,所以这两个线程内部的变量是独立的,互不影响。这样写代码不需要用到同步。
public class helloThread extends Thread {private String str;public int i = 0;public helloThread(String str){this.str = str;}public void run(){ for(int j=0;j<50;j++)System.out.println(str + " :" + (++i));} public static void main(String[] args){new helloThread("线程A").start();new helloThread("线程B").start();}}
打印结果如下:
线程A :1
线程B :1
线程A :2
线程B :2
线程B :3
线程A :3
线程B :4
线程A :4
线程B :5
线程A :5
但如果代码是这样的:
class myRunnable implements Runnable{ public int i = 0;@Overridepublic void run() { // TODO Auto-generated method stub for(int j=0;j<5;j++)System.out.println(Thread.currentThread().getName() +" :" + (++i));}}public class helloThread {public static void main(String[] args){myRunnable tx = new myRunnable();Thread A = new Thread(tx, "线程A");Thread B = new Thread(tx, "线程B"); A.start(); B.start();}}
这段代码的执行结果如下:
线程A :1
线程A :2
线程A :3
线程A :4
线程A :5
线程B :6
线程B :7
线程B :8
线程B :9
线程B :10
可见主线程创建的两个子线程共用同一个Runnbale实例,这里才会用到同步的概念。
还有一点必须注意,这里启动线程是用的start函数,只有它才会启动新的线程,并创建线程栈,而run只是简单的函数调用,它执行在主线程中。这点很关键。
当涉及到线程同步时,如果不是合理的使用锁还会出现死锁,也是android anr发生的原因之一。具体可参考文章如下http://www.cnblogs.com/riskyer/p/3263032.html
class myRunnable implements Runnable{ public int i = 10;@Overridepublic void run() { // TODO Auto-generated method stubSystem.out.println(Thread.currentThread().getName() + " run");for(;;){if(i<=0) break;i = i - 1;try{System.out.println(Thread.currentThread().getName() + " begin sleep.." + i);Thread.sleep(1);System.out.println(Thread.currentThread().getName() + " end sleep.." + i);}catch(InterruptedException e){e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " :" + i);}}}public class helloThread {public static void main(String[] args){myRunnable tx = new myRunnable();Thread A = new Thread(tx, "线程A");Thread B = new Thread(tx, "线程B"); A.start(); B.start();}}
加锁后代码如下:
class myRunnable implements Runnable{ public int i = 10;@Overridepublic void run() { // TODO Auto-generated method stubSystem.out.println(Thread.currentThread().getName() + " run");for(;;){synchronized(this){if(i>=1){ try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} System.out.println(Thread.currentThread().getName() + " are selling ticket :" + i); i--;}}}}}public class helloThread {public static void main(String[] args){myRunnable tx = new myRunnable();Thread A = new Thread(tx, "线程A");Thread B = new Thread(tx, "线程B"); A.start(); B.start();}}
说说我的多线程同步的理解:还是以卖火车票为例,售票员A和B分别在两个售票窗口卖票,A和B就相当于代码中的两个线程,售票系统就相当于主线程,余票总额相当于代码中的变量i,当A和B吃饱饭准备工作,相当于线程调用了start()函数起来了。以临界值分析,当A在卖最后一张票的时候,进入循环,但是还没有i--的操作,此时A突然困了,心情不好了,不干了,此时B也在卖票,他不知道A也在卖最后一张票,售票系统的默认机制是处理B的售票请求,此时B卖出了最后一张票,i--,i=0,这个时候A突然想明白了,接着刚才的工作继续卖票,此时他就卖出了第0张票。要想避免这种情况发生,就是在A不干的时候,让售票系统将i锁起来,其他售票员无法操作i,这样其他人就不能卖票了,只有当A卖完了票,其他人才可以操作。这就是锁的概念。线程同步就是让线程对资源的使用有顺序性,A使用完资源后B才能继续使用。
另外关注几个函数:
Thread.yield():让线程从运行状态变为可运行状态。
Thread.join():比如Thread a = new Thread(); a.start(); a.join() 表示线程a执行完后才能执行其它线程。
Thread.sleep():线程睡眠,保持对象锁。
Thread.wait():线程睡眠,释放对象锁。
- android anr本质分析及解决办法
- Android开发中ANR详解及解决办法
- Android ANR产生原因及解决办法
- Android ANR介绍及分析ANR log信息的方法
- Android-ANR-Android ANR分析
- Android重点知识(四)ANR异常及解决办法
- android ANR产生情况、发生原因及解决办法
- 浅谈ANR及log分析ANR
- 浅谈ANR及如何分析解决ANR
- 浅谈ANR及log分析ANR
- 浅谈ANR及log分析ANR
- 浅谈ANR及log分析ANR
- 浅谈ANR及log分析ANR
- 浅谈ANR及如何分析解决ANR
- 浅谈ANR及如何分析解决ANR
- 浅谈ANR及log分析ANR
- 浅谈ANR及如何分析解决ANR
- 浅谈ANR及log分析ANR
- 【bzoj 2006】: [NOI2010]超级钢琴
- unity 部分知识小集合
- 设计模式大总结
- 用printf输出 STL string数据类型
- 想学JS的原型和闭包吗?COME ON(5)
- android anr本质分析及解决办法
- Looper,Message,Handler概述
- Adding the Action Bar - Overlaying the Action Bar
- 在数学中一个非凸的最优化问题
- 想学JS的原型和闭包吗?COME ON(6)
- 关键词随机飞入飞出效果
- keil分散加载的例子
- Android手势缩放图片以及图片黏贴在手指随手势移动
- .NET — Examples of use (连接池,更新blob字段,事件,备份,恢复,取数据库系统信息)