精华内容
下载资源
问答
  • ANR处理

    2017-07-08 14:05:08
    1 ANR简介 在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个...所以一个流畅的合理的应用程序中不能出现anr,而让用户每次都要处理这个对话框。 1)类型 ANR一般分为三种类型 (1)Key
    1 ANR简介
    在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。用户可以选择“等待”而让程序继续运行,也可以选择“强制关闭”。所以一个流畅的合理的应用程序中不能出现anr,而让用户每次都要处理这个对话框。
    1)类型
    ANR一般分为三种类型
    (1)KeyDispatchTimeout(5s)按键或触摸事件在特定时间内无响应
    (2)BroadcastTimeout(10s)BroadcastReceiver在特定时间内无法完成处理
    (3)ServiceTimeout(20s)Service在特定的时间内无法完成处理(小概率事件)
    2)原因
    由上述的类型,可以看出,当按键或触摸事件在特定的时间内无响应,或者BroadcastReceiver和Service在特定的时间内无法完成处理。就会出现ANR。具体的超时时间的定义在framework下的ActivityManagerService.java中定义的
    如:staticfinal int KEY_DISPATCHING_TIMEOUT = 5*1000
    ANR可能是由主线程导致也可能是由非主线程导致:
    由于主线程导致的情况:
    1.耗时网络访问
    2.当有大量数据读写操作时再请求数据读写
    3.数据库操作(比如其他大数据量应用访问数据库导致数据库负载过重时)
    4.硬件操作(比如Camera)
    5.调用thread_join() / Sleep() / Wait() 或者等待locker的时候
    6.Service binder数量达到上限
    7.在system_server中发生WatchDog ANR
    8.Service忙导致超时无响应
    由于非主线程导致的情况:
    1.非主线程持有lock,导致主线程等待lock超时
    2.非主线程终止或者崩溃导致主线程一直等待
    2避免ANR的措施
    下面研究一下如何最佳构建应用程序来避免ANR。
    1:UI线程尽量只做跟UI相关的工作。Android应用程序通常是运行在一个单独的线程(例如,main)里。这意味着你的应用程序所做的事情如果在主线程里占用了太长的时间的话,就会引发ANR对话框,因为你的应用程序并没有给自己机会来处理输入事件或者Intent广播。因此,UI线程尽量只做跟UI相关的工作。
    2:耗时的工作放到单独的线程里。特别是,Activity应该在它的关键生命周期方法(如onCreate()和onResume())里尽可能少的去做创建操作。潜在的耗时操作,例如网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里(或者以数据库操作为例,通过异步请求的方式)来完成。
    3:尽量用Handler来处理UIthread和别的thread之间的交互,不是说你的主线程阻塞在那里等待子线程的完成——也不是调用Thread.wait()或是Thread.sleep()。替代的方法是,主线程应该为子线程提供一个Handler,以便完成时能够提交给主线程。以这种方式设计你的应用程序,将能保证你的主线程保持对输入的响应性并能避免由于5秒输入事件的超时引发的ANR对话框。这种做法应该在其它显示UI的线程里效仿,因为它们都受相同的超时影响。
    4:IntentReceiver执行时间的特殊限制意味着它应该做:在后台里做小的、琐碎的工作如保存设定或者注册一个Notification。和在主线程里调用的其它方法一样,应用程序应该避免在BroadcastReceiver里做耗时的操作或计算。但不再是在子线程里做这些任务(因为BroadcastReceiver的生命周期短),替代的是,如果响应Intent广播需要执行一个耗时的动作的话,应用程序应该启动一个Service。顺便提及一句,你也应该避免在IntentReceiver里启动一个Activity,因为它会创建一个新的画面,并从当前用户正在运行的程序上抢夺焦点。如果你的应用程序在响应Intent广播时需要向用户展示什么,你应该使用Notification Manager来实现。
    3分析ANR
    1:首先分析log
    2: 从trace.txt文件查看调用stack.
    3: 看代码
    4:仔细查看ANR的成因
    查看是有什么引起的iowait?block?还是memoryleak?
    展开全文
  • ANR 处理

    2016-12-08 10:30:00
    (1)当前的事件没有机会得到处理(即UI线程正在处理前一个事件,没有及时的完成或者looper被某种原因阻塞住了) (2)当前的事件正在处理,但没有及时完成 五:如何避免 KeyDispatchTimeout 1 : UI 线程尽量...

    一:什么是ANR

    ANR:Application Not Responding,即应用无响应

    二:ANR的类型

    ANR一般有三种类型:

    1:KeyDispatchTimeout(5 seconds) --主要类型

    按键或触摸事件在特定时间内无响应

    2BroadcastTimeout(10 seconds)

    BroadcastReceiver在特定时间内无法处理完成

    3:ServiceTimeout(20 seconds) --小概率类型

    Service在特定的时间内无法处理完成

    三:KeyDispatchTimeout

    Akey or touch event was not dispatched within the specified time(按键或触摸事件在特定时间内无响应)

    具体的超时时间的定义在framework下的

    ActivityManagerService.Java

    //How long we wait until we timeout on key dispatching.

    staticfinal int KEY_DISPATCHING_TIMEOUT = 5*1000

    四:为什么会超时呢?

    超时时间的计数一般是从按键分发给app开始。超时的原因一般有两种

    (1)当前的事件没有机会得到处理(即UI线程正在处理前一个事件,没有及时的完成或者looper被某种原因阻塞住了)

    (2)当前的事件正在处理,但没有及时完成

    五:如何避免KeyDispatchTimeout

    1UI线程尽量只做跟UI相关的工作

    2:耗时的工作(比如数据库操作,I/O,连接网络或者别的有可能阻碍UI线程的操作)把它放入单独的线程处理

    3:尽量用Handler来处理UIthread和别的thread之间的交互

     

    六:UI线程

    说了那么多的UI线程,那么哪些属于UI线程呢?

    UI线程主要包括如下:

    1. Activity:onCreate(), onResume(), onDestroy(), onKeyDown(), onClick(),etc

    2. AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel,etc

    3. Mainthread handler: handleMessage(), post*(runnable r), etc

    4. other

    七:如何去分析ANR

    先看个LOG:

    04-01 13:12:11.572 I/InputDispatcher( 220): Application is not responding:Window{2b263310com.Android.email/com.android.email.activity.SplitScreenActivitypaused=false}.  5009.8ms since event, 5009.5ms since waitstarted

    04-0113:12:11.572 I/WindowManager( 220): Input event dispatching timedout sending tocom.android.email/com.android.email.activity.SplitScreenActivity

    04-01 13:12:14.123 I/Process(  220): Sending signal. PID: 21404 SIG: 3---发生ANR的时间和生成trace.txt的时间

    04-01 13:12:14.123 I/dalvikvm(21404):threadid=4: reacting to signal 3 

    ……

    04-0113:12:15.872 E/ActivityManager(  220): ANR in com.android.email(com.android.email/.activity.SplitScreenActivity)

    04-0113:12:15.872 E/ActivityManager(  220): Reason:keyDispatchingTimedOut

    04-0113:12:15.872 E/ActivityManager(  220): Load: 8.68 / 8.37 / 8.53

    04-0113:12:15.872 E/ActivityManager(  220):CPUusage from 4361ms to 699ms ago----CPU在ANR发生前的使用情况

     

    04-0113:12:15.872 E/ActivityManager(  220):   5.5%21404/com.android.email: 1.3% user + 4.1% kernel / faults: 10 minor

    04-0113:12:15.872 E/ActivityManager(  220):   4.3%220/system_server: 2.7% user + 1.5% kernel / faults: 11 minor 2 major

    04-0113:12:15.872 E/ActivityManager(  220):   0.9%52/spi_qsd.0: 0% user + 0.9% kernel

    04-0113:12:15.872 E/ActivityManager(  220):   0.5%65/irq/170-cyttsp-: 0% user + 0.5% kernel

    04-0113:12:15.872 E/ActivityManager(  220):   0.5%296/com.android.systemui: 0.5% user + 0% kernel

    04-0113:12:15.872 E/ActivityManager(  220): 100%TOTAL: 4.8% user + 7.6% kernel + 87% iowait

    04-0113:12:15.872 E/ActivityManager(  220):CPUusage from 3697ms to 4223ms later:-- ANR后CPU的使用量

    04-0113:12:15.872 E/ActivityManager(  220):   25%21404/com.android.email: 25% user + 0% kernel / faults: 191 minor

    04-0113:12:15.872 E/ActivityManager(  220):    16% 21603/__eas(par.hakan: 16% user + 0% kernel

    04-0113:12:15.872 E/ActivityManager(  220):    7.2% 21406/GC: 7.2% user + 0% kernel

    04-0113:12:15.872 E/ActivityManager(  220):    1.8% 21409/Compiler: 1.8% user + 0% kernel

    04-0113:12:15.872 E/ActivityManager(  220):   5.5%220/system_server: 0% user + 5.5% kernel / faults: 1 minor

    04-0113:12:15.872 E/ActivityManager(  220):    5.5% 263/InputDispatcher: 0% user + 5.5% kernel

    04-0113:12:15.872 E/ActivityManager(  220): 32%TOTAL: 28% user + 3.7% kernel

     

    从LOG可以看出ANR的类型,CPU的使用情况,如果CPU使用量接近100%,说明当前设备很忙,有可能是CPU饥饿导致了ANR

    如果CPU使用量很少,说明主线程被BLOCK了

    如果IOwait很高,说明ANR有可能是主线程在进行I/O操作造成的

    除了看LOG,解决ANR还得需要trace.txt文件,

    如何获取呢?可以用如下命令获取

    1. $chmod 777 /data/anr

    2. $rm /data/anr/traces.txt

    3. $ps

    4. $kill -3PID

    5. adbpull data/anr/traces.txt ./mytraces.txt

    从trace.txt文件,看到最多的是如下的信息:

    -----pid 21404 at 2011-04-0113:12:14 -----  
    Cmdline: com.android.email

    DALVIK THREADS:
    (mutexes: tll=0tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)
    "main" prio=5 tid=1NATIVE
      | group="main" sCount=1 dsCount=0obj=0x2aad2248 self=0xcf70
      | sysTid=21404 nice=0 sched=0/0cgrp=[fopen-error:2] handle=1876218976
      atandroid.os.MessageQueue.nativePollOnce(Native Method)
      atandroid.os.MessageQueue.next(MessageQueue.java:119)
      atandroid.os.Looper.loop(Looper.java:110
    )
     at android.app.ActivityThread.main(ActivityThread.java:3688)
     at java.lang.reflect.Method.invokeNative(Native Method)
      atjava.lang.reflect.Method.invoke(Method.java:507)
      atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:624)
     at dalvik.system.NativeStart.main(Native Method)

    说明主线程在等待下条消息进入消息队列

    八:Thread状态

    ThreadState (defined at “dalvik/vm/thread.h “)

    THREAD_UNDEFINED = -1, /* makes enum compatible with int32_t */

    THREAD_ZOMBIE = 0, /* TERMINATED */

    THREAD_RUNNING = 1, /* RUNNABLE or running now */

    THREAD_TIMED_WAIT = 2, /* TIMED_WAITING in Object.wait() */

    THREAD_MONITOR = 3, /* BLOCKED on a monitor */

    THREAD_WAIT = 4, /* WAITING in Object.wait() */

    THREAD_INITIALIZING= 5, /* allocated, not yet running */

    THREAD_STARTING = 6, /* started, not yet on thread list */

    THREAD_NATIVE = 7, /* off in a JNI native method */

    THREAD_VMWAIT = 8, /* waiting on a VM resource */

    THREAD_SUSPENDED = 9, /* suspended, usually by GC or debugger */

     

    九:如何调查并解决ANR

    1:首先分析log

    2: 从trace.txt文件查看调用stack.

    3: 看代码

    4:仔细查看ANR的成因(iowait?block?memoryleak?)

     

     

    十:案例

    案例1:关键词:ContentResolver in AsyncTask onPostExecute, high iowait

    Process:com.android.email
    Activity:com.android.email/.activity.MessageView
    Subject:keyDispatchingTimedOut
    CPU usage from 2550ms to -2814ms ago:
    5%187/system_server: 3.5% user + 1.4% kernel / faults: 86 minor 20major
    4.4% 1134/com.android.email: 0.7% user + 3.7% kernel /faults: 38 minor 19 major
    4% 372/com.android.eventstream: 0.7%user + 3.3% kernel / faults: 6 minor
    1.1% 272/com.android.phone:0.9% user + 0.1% kernel / faults: 33 minor
    0.9%252/com.android.systemui: 0.9% user + 0% kernel
    0%409/com.android.eventstream.telephonyplugin: 0% user + 0% kernel /faults: 2 minor
    0.1% 632/com.android.devicemonitor: 0.1% user + 0%kernel
    100%TOTAL: 6.9% user + 8.2% kernel +84%iowait


    -----pid 1134 at 2010-12-17 17:46:51 -----
    Cmd line:com.android.email

    DALVIK THREADS:
    (mutexes: tll=0 tsl=0tscl=0 ghl=0 hwl=0 hwll=0)
    "main" prio=5 tid=1 WAIT
    |group="main" sCount=1 dsCount=0 obj=0x2aaca180self=0xcf20
    | sysTid=1134 nice=0 sched=0/0 cgrp=[fopen-error:2]handle=1876218976
    at java.lang.Object.wait(Native Method)
    -waiting on <0x2aaca218> (a java.lang.VMThread)
    atjava.lang.Thread.parkFor(Thread.java:1424)
    atjava.lang.LangAccessImpl.parkFor(LangAccessImpl.java:48)
    atsun.misc.Unsafe.park(Unsafe.java:337)
    atjava.util.concurrent.locks.LockSupport.park(LockSupport.java:157)
    atjava.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:808)
    atjava.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:841)
    atjava.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1171)
    atjava.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:200)
    atjava.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:261)
    atandroid.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:378)
    atandroid.database.sqlite.SQLiteCursor.<init>(SQLiteCursor.java:222)
    atandroid.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:53)
    atandroid.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1356)
    atandroid.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1235)
    atandroid.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1189)
    atandroid.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1271)
    atcom.android.email.provider.EmailProvider.query(EmailProvider.java:1098)
    atandroid.content.ContentProvider$Transport.query(ContentProvider.java:187)
    atandroid.content.ContentResolver.query(ContentResolver.java:268)
    atcom.android.email.provider.EmailContent$Message.restoreMessageWithId(EmailContent.java:648)
    atcom.android.email.Controller.setMessageRead(Controller.java:658)
    atcom.android.email.activity.MessageView.onMarkAsRead(MessageView.java:700)
    atcom.android.email.activity.MessageView.access$2500(MessageView.java:98)
    atcom.android.email.activity.MessageView$LoadBodyTask.onPostExecute(MessageView.java:1290)
    atcom.android.email.activity.MessageView$LoadBodyTask.onPostExecute(MessageView.java:1255)
    atandroid.os.AsyncTask.finish(AsyncTask.java:417)
    atandroid.os.AsyncTask.access$300(AsyncTask.java:127)
    atandroid.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
    atandroid.os.Handler.dispatchMessage(Handler.java:99)
    atandroid.os.Looper.loop(Looper.java:123)
    atandroid.app.ActivityThread.main(ActivityThread.java:3652)
    atjava.lang.reflect.Method.invokeNative(Native Method)
    atjava.lang.reflect.Method.invoke(Method.java:507)
    atcom.android.internal.os.ZygoteIn

    原因:IOWait很高,说明当前系统在忙于I/O,因此数据库操作被阻塞

    原来:

    finalMessagemessage=Message.restoreMessageWithId(mProviderContext,messageId);
    if(message==null){
       return;
    }

    Accountaccount=Account.restoreAccountWithId(mProviderContext,message.mAccountKey);

    if(account==null){
       return;//isMessagingController returns false for null, but let's make itclear.
    }

    if(isMessagingController(account)){
       new Thread(){
           @Override
           public void run(){
              mLegacyController.processPendingActions(message.mAccountKey);
           }
       }.start();
    }

    解决后:

     

    newThread() {
        finalMessagemessage=Message.restoreMessageWithId(mProviderContext,messageId);

        if(message==null){
            return;
        }

        Accountaccount=Account.restoreAccountWithId(mProviderContext,message.mAccountKey);

        if(account==null){
           return;//isMessagingController returns false for null, but let's make itclear.
        }

        if(isMessagingController(account)) {
            mLegacyController.processPendingActions(message.mAccountKey);
        }
    }.start();

     

    关于AsyncTask:http://developer.android.com/reference/android/os/AsyncTask.html

     

    案例2:关键词:在UI线程进行网络数据的读写

    ANRin process: com.android.mediascape:PhotoViewer (last incom.android.mediascape:PhotoViewer)
    Annotation:keyDispatchingTimedOut
    CPU usage:
    Load: 6.74 / 6.89 / 6.12
    CPUusage from 8254ms to 3224ms ago:
    ovider.webmedia: 4% = 4% user +0% kernel / faults: 68 minor
    system_server: 2% = 1% user + 0%kernel / faults: 18 minor
    re-initialized>: 0% = 0% user + 0%kernel / faults: 50 minor
    events/0: 0% = 0% user + 0%kernel
    TOTAL:7% = 6% user + 1% kernel

    DALVIKTHREADS:
    ""main"" prio=5 tid=3 NATIVE
    |group=""main"" sCount=1 dsCount=0 s=Yobj=0x4001b240 self=0xbda8
    | sysTid=2579 nice=0 sched=0/0cgrp=unknown handle=-1343993184
    atorg.apache.harmony.luni.platform.OSNetworkSystem.receiveStreamImpl(NativeMethod)
    atorg.apache.harmony.luni.platform.OSNetworkSystem.receiveStream(OSNetworkSystem.java:478)
    atorg.apache.harmony.luni.NET.PlainSocketImpl.read(PlainSocketImpl.java:565)
    atorg.apache.harmony.luni.Net.SocketInputStream.read(SocketInputStream.java:87)
    atorg.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnection$LimitedInputStream.read(HttpURLConnection.java:303)
    atjava.io.InputStream.read(InputStream.java:133)
    atjava.io.BufferedInputStream.fillbuf(BufferedInputStream.java:157)
    atjava.io.BufferedInputStream.read(BufferedInputStream.java:346)
    atandroid.graphics.BitmapFactory.nativeDecodeStream(Native Method)
    atandroid.graphics.BitmapFactory.decodeStream(BitmapFactory.java:459)
    atcom.android.mediascape.activity.PhotoViewerActivity.getPreviewImage(PhotoViewerActivity.java:4465)
    atcom.android.mediascape.activity.PhotoViewerActivity.dispPreview(PhotoViewerActivity.java:4406)
    atcom.android.mediascape.activity.PhotoViewerActivity.access$6500(PhotoViewerActivity.java:125)
    atcom.android.mediascape.activity.PhotoViewerActivity$33$1.run(PhotoViewerActivity.java:4558)
    atandroid.os.Handler.handleCallback(Handler.java:587)
    atandroid.os.Handler.dispatchMessage(Handler.java:92)
    atandroid.os.Looper.loop(Looper.java:123)
    atandroid.app.ActivityThread.main(ActivityThread.java:4370)
    atjava.lang.reflect.Method.invokeNative(Native Method)
    atjava.lang.reflect.Method.invoke(Method.java:521)
    atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    atdalvik.system.NativeStart.main(Native Method)

    关于网络连接,在设计的时候可以设置个timeout的时间或者放入独立的线程来处理。

    关于Handler的问题,可以参考:http://developer.android.com/reference/android/os/Handler.html

    案例3:

    关键词:Memoryleak/Thread leak

    11-1621:41:42.560 I/ActivityManager( 1190): ANR in process:android.process.acore (last in android.process.acore)
    11-1621:41:42.560 I/ActivityManager( 1190): Annotation:keyDispatchingTimedOut
    11-16 21:41:42.560 I/ActivityManager(1190): CPU usage:
    11-16 21:41:42.560 I/ActivityManager( 1190):Load: 11.5 / 11.1 / 11.09
    11-16 21:41:42.560 I/ActivityManager(1190): CPU usage from 9046ms to 4018ms ago:
    11-16 21:41:42.560I/ActivityManager( 1190): d.process.acore:98%= 97% user + 0% kernel / faults: 1134 minor
    11-16 21:41:42.560I/ActivityManager( 1190): system_server: 0% = 0% user + 0% kernel /faults: 1 minor
    11-16 21:41:42.560 I/ActivityManager( 1190): adbd:0% = 0% user + 0% kernel
    11-16 21:41:42.560 I/ActivityManager(1190): logcat: 0% = 0% user + 0% kernel
    11-16 21:41:42.560I/ActivityManager( 1190): TOTAL:100% = 98% user + 1% kernel

    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)
    atandroid.view.ViewGroup.drawChild(ViewGroup.java:1541)
    ……
    atcom.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1830)
    atandroid.view.ViewRoot.draw(ViewRoot.java:1349)
    atandroid.view.ViewRoot.performTraversals(ViewRoot.java:1114)
    atandroid.view.ViewRoot.handleMessage(ViewRoot.java:1633)
    atandroid.os.Handler.dispatchMessage(Handler.java:99)
    atandroid.os.Looper.loop(Looper.java:123)
    atandroid.app.ActivityThread.main(ActivityThread.java:4370)
    atjava.lang.reflect.Method.invokeNative(Native Method)
    atjava.lang.reflect.Method.invoke(Method.java:521)
    atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    atdalvik.system.NativeStart.main(Native Method)

    "Thread-408"prio=5 tid=329 WAIT
    |group="main" sCount=1 dsCount=0 s=N obj=0x46910d40self=0xcd0548
    | sysTid=10602 nice=0 sched=0/0 cgrp=unknownhandle=15470792
    at java.lang.Object.wait(Native Method)
    -waiting on <0x468cd420> (a java.lang.Object)
    atjava.lang.Object.wait(Object.java:288)
    atcom.android.dialer.CallLogContentHelper$UiUpdaterExecutor$1.run(CallLogContentHelper.java:289)
    atjava.lang.Thread.run(Thread.java:1096)

    分析:

    atdalvik.system.VMRuntime.trackExternalAllocation(NativeMethod)内存不足导致block在创建bitmap上

    **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

    解决:如果机器的内存族,可以修改虚拟机的内存为36M或更大,不过最好是复查代码,查看哪些内存没有释放

    转载于:https://my.oschina.net/u/2502529/blog/801929

    展开全文
  • anr处理

    千次阅读 2012-09-25 17:54:24
    一:什么是ANR ANR:Application Not Responding,即应用无响应 二:ANR的类型 ANR一般有三种类型: 1:KeyDispatchTimeout(5 seconds) --主要类型 按键或触摸事件在特定时间内无响应 2:Broadcast...

    一:什么是ANR

    ANR:Application Not Responding,即应用无响应

    二:ANR的类型

    ANR一般有三种类型:

    1KeyDispatchTimeout(5 seconds) --主要类型

    按键或触摸事件在特定时间内无响应

    2BroadcastTimeout(10 seconds)

    BroadcastReceiver在特定时间内无法处理完成

    3ServiceTimeout(20 seconds) --小概率类型

    Service在特定的时间内无法处理完成

    三:KeyDispatchTimeout

    Akey or touch event was not dispatched within the specified time(按键或触摸事件在特定时间内无响应)

    具体的超时时间的定义在framework下的

    ActivityManagerService.java

    //How long we wait until we timeout on key dispatching.

    staticfinal int KEY_DISPATCHING_TIMEOUT = 5*1000

    四:为什么会超时呢?

    超时时间的计数一般是从按键分发给app开始。超时的原因一般有两种

    (1)当前的事件没有机会得到处理(即UI线程正在处理前一个事件,没有及时的完成或者looper被某种原因阻塞住了)

    (2)当前的事件正在处理,但没有及时完成

    五:如何避免KeyDispatchTimeout

    1UI线程尽量只做跟UI相关的工作

    2:耗时的工作(比如数据库操作,I/O,连接网络或者别的有可能阻碍UI线程的操作)把它放入单独的线程处理

    3:尽量用Handler来处理UIthread和别的thread之间的交互


    六:UI线程

    说了那么多的UI线程,那么哪些属于UI线程呢?

    UI线程主要包括如下:

    1. Activity:onCreate(), onResume(), onDestroy(), onKeyDown(), onClick(),etc

    2. AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel,etc

    3. Mainthread handler: handleMessage(), post*(runnable r), etc

    4. other

    :如何去分析ANR

    先看个LOG:

    04-01 13:12:11.572 I/InputDispatcher( 220): Application is not responding:Window{2b263310com.android.email/com.android.email.activity.SplitScreenActivitypaused=false}.  5009.8ms since event, 5009.5ms since waitstarted

    04-0113:12:11.572 I/WindowManager( 220): Input event dispatching timedout sending tocom.android.email/com.android.email.activity.SplitScreenActivity

    04-01 13:12:14.123 I/Process(  220): Sending signal. PID: 21404 SIG: 3---发生ANR的时间和生成trace.txt的时间

    04-01 13:12:14.123 I/dalvikvm(21404):threadid=4: reacting to signal 3 

    ……

    04-0113:12:15.872 E/ActivityManager(  220): ANR in com.android.email(com.android.email/.activity.SplitScreenActivity)

    04-0113:12:15.872 E/ActivityManager(  220): Reason:keyDispatchingTimedOut

    04-0113:12:15.872 E/ActivityManager(  220): Load: 8.68 / 8.37 / 8.53

    04-0113:12:15.872 E/ActivityManager(  220):CPUusage from 4361ms to 699ms ago----CPUANR发生前的使用情况


    04-0113:12:15.872 E/ActivityManager(  220):   5.5%21404/com.android.email: 1.3% user + 4.1% kernel / faults: 10 minor

    04-0113:12:15.872 E/ActivityManager(  220):   4.3%220/system_server: 2.7% user + 1.5% kernel / faults: 11 minor 2 major

    04-0113:12:15.872 E/ActivityManager(  220):   0.9%52/spi_qsd.0: 0% user + 0.9% kernel

    04-0113:12:15.872 E/ActivityManager(  220):   0.5%65/irq/170-cyttsp-: 0% user + 0.5% kernel

    04-0113:12:15.872 E/ActivityManager(  220):   0.5%296/com.android.systemui: 0.5% user + 0% kernel

    04-0113:12:15.872 E/ActivityManager(  220): 100%TOTAL: 4.8% user + 7.6% kernel + 87% iowait

    04-0113:12:15.872 E/ActivityManager(  220):CPUusage from 3697ms to 4223ms later:-- ANRCPU的使用量

    04-0113:12:15.872 E/ActivityManager(  220):   25%21404/com.android.email: 25% user + 0% kernel / faults: 191 minor

    04-0113:12:15.872 E/ActivityManager(  220):    16% 21603/__eas(par.hakan: 16% user + 0% kernel

    04-0113:12:15.872 E/ActivityManager(  220):    7.2% 21406/GC: 7.2% user + 0% kernel

    04-0113:12:15.872 E/ActivityManager(  220):    1.8% 21409/Compiler: 1.8% user + 0% kernel

    04-0113:12:15.872 E/ActivityManager(  220):   5.5%220/system_server: 0% user + 5.5% kernel / faults: 1 minor

    04-0113:12:15.872 E/ActivityManager(  220):    5.5% 263/InputDispatcher: 0% user + 5.5% kernel

    04-0113:12:15.872 E/ActivityManager(  220): 32%TOTAL: 28% user + 3.7% kernel


    LOG可以看出ANR的类型,CPU的使用情况,如果CPU使用量接近100%,说明当前设备很忙,有可能是CPU饥饿导致了ANR

    如果CPU使用量很少,说明主线程被BLOCK

    如果IOwait很高,说明ANR有可能是主线程在进行I/O操作造成的

    除了看LOG,解决ANR还得需要trace.txt文件,

    如何获取呢?可以用如下命令获取

    1. $chmod 777 /data/anr

    2. $rm /data/anr/traces.txt

    3. $ps

    4. $kill -3PID

    5. adbpull data/anr/traces.txt ./mytraces.txt

    trace.txt文件,看到最多的是如下的信息:

    -----pid 21404 at 2011-04-0113:12:14 -----  
    Cmdline: com.android.email

    DALVIK THREADS:
    (mutexes: tll=0tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)
    "main" prio=5 tid=1NATIVE
      | group="main" sCount=1 dsCount=0obj=0x2aad2248 self=0xcf70
      | sysTid=21404 nice=0 sched=0/0cgrp=[fopen-error:2] handle=1876218976
      atandroid.os.MessageQueue.nativePollOnce(Native Method)
      atandroid.os.MessageQueue.next(MessageQueue.java:119)
      atandroid.os.Looper.loop(Looper.java:110
    )
     at android.app.ActivityThread.main(ActivityThread.java:3688)
     at java.lang.reflect.Method.invokeNative(Native Method)
      atjava.lang.reflect.Method.invoke(Method.java:507)
      atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:624)
     at dalvik.system.NativeStart.main(Native Method)

    说明主线程在等待下条消息进入消息队列

    八:Thread状态

    ThreadState (defined at “dalvik/vm/thread.h “)

    THREAD_UNDEFINED = -1, /* makes enum compatible with int32_t */

    THREAD_ZOMBIE = 0, /* TERMINATED */

    THREAD_RUNNING = 1, /* RUNNABLE or running now */

    THREAD_TIMED_WAIT = 2, /* TIMED_WAITING in Object.wait() */

    THREAD_MONITOR = 3, /* BLOCKED on a monitor */

    THREAD_WAIT = 4, /* WAITING in Object.wait() */

    THREAD_INITIALIZING= 5, /* allocated, not yet running */

    THREAD_STARTING = 6, /* started, not yet on thread list */

    THREAD_NATIVE = 7, /* off in a JNI native method */

    THREAD_VMWAIT = 8, /* waiting on a VM resource */

    THREAD_SUSPENDED = 9, /* suspended, usually by GC or debugger */


    九:如何调查并解决ANR

    1:首先分析log

    2: trace.txt文件查看调用stack.

    3: 看代码

    4:仔细查看ANR的成因(iowait?block?memoryleak?


    十:案例

    案例1关键词:ContentResolver in AsyncTask onPostExecute, highiowait

    Process:com.android.email
    Activity:com.android.email/.activity.MessageView
    Subject:keyDispatchingTimedOut
    CPU usage from 2550ms to -2814ms ago:
    5%187/system_server: 3.5% user + 1.4% kernel / faults: 86 minor 20major
    4.4% 1134/com.android.email: 0.7% user + 3.7% kernel /faults: 38 minor 19 major
    4% 372/com.android.eventstream: 0.7%user + 3.3% kernel / faults: 6 minor
    1.1% 272/com.android.phone:0.9% user + 0.1% kernel / faults: 33 minor
    0.9%252/com.android.systemui: 0.9% user + 0% kernel
    0%409/com.android.eventstream.telephonyplugin: 0% user + 0% kernel /faults: 2 minor
    0.1% 632/com.android.devicemonitor: 0.1% user + 0%kernel
    100%TOTAL: 6.9% user + 8.2% kernel +84%iowait


    -----pid 1134 at 2010-12-17 17:46:51 -----
    Cmd line:com.android.email

    DALVIK THREADS:
    (mutexes: tll=0 tsl=0tscl=0 ghl=0 hwl=0 hwll=0)
    "main" prio=5 tid=1 WAIT
    |group="main" sCount=1 dsCount=0 obj=0x2aaca180self=0xcf20
    | sysTid=1134 nice=0 sched=0/0 cgrp=[fopen-error:2]handle=1876218976
    at java.lang.Object.wait(Native Method)
    -waiting on <0x2aaca218> (a java.lang.VMThread)
    atjava.lang.Thread.parkFor(Thread.java:1424)
    atjava.lang.LangAccessImpl.parkFor(LangAccessImpl.java:48)
    atsun.misc.Unsafe.park(Unsafe.java:337)
    atjava.util.concurrent.locks.LockSupport.park(LockSupport.java:157)
    atjava.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:808)
    atjava.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:841)
    atjava.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1171)
    atjava.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:200)
    atjava.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:261)
    atandroid.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:378)
    atandroid.database.sqlite.SQLiteCursor.<init>(SQLiteCursor.java:222)
    atandroid.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:53)
    atandroid.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1356)
    atandroid.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1235)
    atandroid.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1189)
    atandroid.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1271)
    atcom.android.email.provider.EmailProvider.query(EmailProvider.java:1098)
    atandroid.content.ContentProvider$Transport.query(ContentProvider.java:187)
    atandroid.content.
    ContentResolver.query(ContentResolver.java:268)
    atcom.android.email.provider.EmailContent$Message.restoreMessageWithId(EmailContent.java:648)
    atcom.android.email.Controller.setMessageRead(Controller.java:658)
    atcom.android.email.activity.MessageView.onMarkAsRead(MessageView.java:700)
    atcom.android.email.activity.MessageView.access$2500(MessageView.java:98)
    at
    com.android.email.activity.MessageView$LoadBodyTask.onPostExecute(MessageView.java:1290)
    atcom.android.email.activity.MessageView$LoadBodyTask.onPostExecute(MessageView.java:1255)
    atandroid.os.AsyncTask.finish(AsyncTask.java:417)
    atandroid.os.AsyncTask.access$300(AsyncTask.java:127)
    at
    android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
    atandroid.os.Handler.dispatchMessage(Handler.java:99)
    atandroid.os.Looper.loop(Looper.java:123)
    atandroid.app.ActivityThread.main(ActivityThread.java:3652)
    atjava.lang.reflect.Method.invokeNative(Native Method)
    atjava.lang.reflect.Method.invoke(Method.java:507)
    atcom.android.internal.os.ZygoteIn

    原因:IOWait很高,说明当前系统在忙于I/O,因此数据库操作被阻塞

    原来:

    finalMessagemessage=Message.restoreMessageWithId(mProviderContext,messageId);
    if(message==null){
       return;
    }

    Accountaccount=Account.restoreAccountWithId(mProviderContext,message.mAccountKey);

    if(account==null){
       return;//isMessagingController returns false for null, but let's make itclear.
    }

    if(isMessagingController(account)){
       new Thread(){
           @Override
           public void run(){
              mLegacyController.processPendingActions(message.mAccountKey);
           }
       }.start();
    }

    解决后:

    newThread() {
        finalMessagemessage=Message.restoreMessageWithId(mProviderContext,messageId);

        if(message==null){
            return;
        }

        Accountaccount=Account.restoreAccountWithId(mProviderContext,message.mAccountKey);

        if(account==null){
           return;//isMessagingController returns false for null, but let's make itclear.
        }

        if(isMessagingController(account)) {
            mLegacyController.processPendingActions(message.mAccountKey);
        }
    }.start();

    关于AsyncTask:http://developer.android.com/reference/android/os/AsyncTask.html


    案例2关键词:UI线程进行网络数据的读写

    ANRin process: com.android.mediascape:PhotoViewer (last incom.android.mediascape:PhotoViewer)
    Annotation:keyDispatchingTimedOut
    CPU usage:
    Load: 6.74 / 6.89 / 6.12
    CPUusage from 8254ms to 3224ms ago:
    ovider.webmedia: 4% = 4% user +0% kernel / faults: 68 minor
    system_server: 2% = 1% user + 0%kernel / faults: 18 minor
    re-initialized>: 0% = 0% user + 0%kernel / faults: 50 minor
    events/0: 0% = 0% user + 0%kernel
    TOTAL:7% = 6% user + 1% kernel

    DALVIKTHREADS:
    ""main"" prio=5 tid=3 NATIVE
    |group=""main"" sCount=1 dsCount=0 s=Yobj=0x4001b240 self=0xbda8
    | sysTid=2579 nice=0 sched=0/0cgrp=unknown handle=-1343993184
    atorg.apache.harmony.luni.platform.OSNetworkSystem.receiveStreamImpl(NativeMethod)
    atorg.apache.harmony.luni.platform.
    OSNetworkSystem.receiveStream(OSNetworkSystem.java:478)
    atorg.apache.harmony.luni.net.PlainSocketImpl.read(PlainSocketImpl.java:565)
    atorg.apache.harmony.luni.net.SocketInputStream.read(SocketInputStream.java:87)
    atorg.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnection$LimitedInputStream.read(HttpURLConnection.java:303)
    atjava.io.InputStream.read(InputStream.java:133)
    atjava.io.BufferedInputStream.fillbuf(BufferedInputStream.java:157)
    atjava.io.BufferedInputStream.read(BufferedInputStream.java:346)
    atandroid.graphics.BitmapFactory.nativeDecodeStream(Native Method)
    atandroid.graphics.
    BitmapFactory.decodeStream(BitmapFactory.java:459)
    atcom.android.mediascape.activity.PhotoViewerActivity.
    getPreviewImage(PhotoViewerActivity.java:4465)
    atcom.android.mediascape.activity.PhotoViewerActivity.
    dispPreview(PhotoViewerActivity.java:4406)
    atcom.android.mediascape.activity.PhotoViewerActivity.access$6500(PhotoViewerActivity.java:125)

    atcom.android.mediascape.activity.PhotoViewerActivity$33$1.run(PhotoViewerActivity.java:4558)
    atandroid.os.Handler.handleCallback(Handler.java:587)
    atandroid.os.Handler.dispatchMessage(Handler.java:92)
    atandroid.os.Looper.loop(Looper.java:123)
    atandroid.app.ActivityThread.main(ActivityThread.java:4370)
    atjava.lang.reflect.Method.invokeNative(Native Method)
    atjava.lang.reflect.Method.invoke(Method.java:521)
    atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    atdalvik.system.NativeStart.main(Native Method)

    关于网络连接,在设计的时候可以设置个timeout的时间或者放入独立的线程来处理。

    关于Handler的问题,可以参考:http://developer.android.com/reference/android/os/Handler.html

    案例3

    关键词:Memoryleak/Thread leak

    11-1621:41:42.560 I/ActivityManager( 1190): ANR in process:android.process.acore (last in android.process.acore)
    11-1621:41:42.560 I/ActivityManager( 1190): Annotation:keyDispatchingTimedOut
    11-16 21:41:42.560 I/ActivityManager(1190): CPU usage:
    11-16 21:41:42.560 I/ActivityManager( 1190):Load: 11.5 / 11.1 / 11.09
    11-16 21:41:42.560 I/ActivityManager(1190): CPU usage from 9046ms to 4018ms ago:
    11-16 21:41:42.560I/ActivityManager( 1190): 
    d.process.acore:98%= 97% user + 0% kernel / faults: 1134 minor
    11-16 21:41:42.560I/ActivityManager( 1190): system_server: 0% = 0% user + 0% kernel /faults: 1 minor
    11-16 21:41:42.560 I/ActivityManager( 1190): adbd:0% = 0% user + 0% kernel
    11-16 21:41:42.560 I/ActivityManager(1190): logcat: 0% = 0% user + 0% kernel
    11-16 21:41:42.560I/ActivityManager( 1190): 
    TOTAL:100% = 98% user + 1% kernel

    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)
    atandroid.view.ViewGroup.drawChild(ViewGroup.java:1541)
    ……
    atcom.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1830)
    atandroid.view.ViewRoot.draw(ViewRoot.java:1349)
    atandroid.view.ViewRoot.performTraversals(ViewRoot.java:1114)
    atandroid.view.ViewRoot.handleMessage(ViewRoot.java:1633)
    atandroid.os.Handler.dispatchMessage(Handler.java:99)
    atandroid.os.Looper.loop(Looper.java:123)
    atandroid.app.ActivityThread.main(ActivityThread.java:4370)
    atjava.lang.reflect.Method.invokeNative(Native Method)
    atjava.lang.reflect.Method.invoke(Method.java:521)
    atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    atdalvik.system.NativeStart.main(Native Method)

    "Thread-408"prio=5 tid=329 WAIT
    |group="main" sCount=1 dsCount=0 s=N obj=0x46910d40self=0xcd0548
    | sysTid=10602 nice=0 sched=0/0 cgrp=unknownhandle=15470792
    at java.lang.Object.wait(Native Method)
    -waiting on <0x468cd420> (a java.lang.Object)
    atjava.lang.Object.wait(Object.java:288)
    atcom.android.dialer.CallLogContentHelper$UiUpdaterExecutor$1.run(CallLogContentHelper.java:289)
    atjava.lang.Thread.run(Thread.java:1096)

    分析:

    atdalvik.system.VMRuntime.trackExternalAllocation(NativeMethod)内存不足导致block在创建bitmap

    **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

    展开全文
  • Android ANR处理

    2019-10-12 10:01:07
    某书时不时就看不了了,不知道是我电脑问题还是啥,我就当个...1, 你碰到ANR了吗 在App使用过程中, 你可能遇到过这样的情况: ANR 恭喜你, 这就是传说中的ANR. 1.1 何为ANR ANR全名Application Not Respondin...

    推荐大家看看大神操作猛如虎的场面:https://www.jianshu.com/p/6d855e984b99

    某书时不时就看不了了,不知道是我电脑问题还是啥,我就当个搬运工,记录下来。

    1, 你碰到ANR了吗

    在App使用过程中, 你可能遇到过这样的情况:

    ANR

    恭喜你, 这就是传说中的ANR.

    1.1 何为ANR

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

    1.2 为什么会产生ANR

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

    • 5s内无法响应用户输入事件(例如键盘输入, 触摸屏幕等).
    • BroadcastReceiver在10s内无法结束.

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

    1.3 如何避免ANR

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

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

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

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

    稍后解答.

    2, ANR分析

    2.1 获取ANR产生的trace文件

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

    可以直接在C盘目录下进行导出:

    C:\Users\Administrator> adb pull data/anr/traces.txt C:\Users\Administrator\Desktop

    2.2.1 普通阻塞导致的ANR

    获取到的tracs.txt文件一般如下:

    如下以GithubApp代码为例, 强行sleep thread产生的一个ANR.

    ----- pid 2976 at 2016-09-08 23:02:47 -----
    Cmd line: com.anly.githubapp  // 最新的ANR发生的进程(包名)
    
    ...
    
    DALVIK THREADS (41):
    "main" prio=5 tid=1 Sleeping
      | group="main" sCount=1 dsCount=0 obj=0x73467fa8 self=0x7fbf66c95000
      | sysTid=2976 nice=0 cgrp=default sched=0/0 handle=0x7fbf6a8953e0
      | state=S schedstat=( 0 0 0 ) utm=60 stm=37 core=1 HZ=100
      | stack=0x7ffff4ffd000-0x7ffff4fff000 stackSize=8MB
      | held mutexes=
      at java.lang.Thread.sleep!(Native method)
      - sleeping on <0x35fc9e33> (a java.lang.Object)
      at java.lang.Thread.sleep(Thread.java:1031)
      - locked <0x35fc9e33> (a java.lang.Object)
      at java.lang.Thread.sleep(Thread.java:985) // 主线程中sleep过长时间, 阻塞导致无响应.
      at com.tencent.bugly.crashreport.crash.c.l(BUGLY:258)
      - locked <@addr=0x12dadc70> (a com.tencent.bugly.crashreport.crash.c)
      at com.tencent.bugly.crashreport.CrashReport.testANRCrash(BUGLY:166)  // 产生ANR的那个函数调用
      - locked <@addr=0x12d1e840> (a java.lang.Class<com.tencent.bugly.crashreport.CrashReport>)
      at com.anly.githubapp.common.wrapper.CrashHelper.testAnr(CrashHelper.java:23)
      at com.anly.githubapp.ui.module.main.MineFragment.onClick(MineFragment.java:80) // ANR的起点
      at com.anly.githubapp.ui.module.main.MineFragment_ViewBinding$2.doClick(MineFragment_ViewBinding.java:47)
      at butterknife.internal.DebouncingOnClickListener.onClick(DebouncingOnClickListener.java:22)
      at android.view.View.performClick(View.java:4780)
      at android.view.View$PerformClick.run(View.java:19866)
      at android.os.Handler.handleCallback(Handler.java:739)
      at android.os.Handler.dispatchMessage(Handler.java:95)
      at android.os.Looper.loop(Looper.java:135)
      at android.app.ActivityThread.main(ActivityThread.java:5254)
      at java.lang.reflect.Method.invoke!(Native method)
      at java.lang.reflect.Method.invoke(Method.java:372)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
    

    拿到trace信息, 一切好说.
    如上trace信息中的添加的中文注释已基本说明了trace文件该怎么分析:

    1. 文件最上的即为最新产生的ANR的trace信息.
    2. 前面两行表明ANR发生的进程pid, 时间, 以及进程名字(包名).
    3. 寻找我们的代码点, 然后往前推, 看方法调用栈, 追溯到问题产生的根源.

    以上的ANR trace是属于相对简单, 还有可能你并没有在主线程中做过于耗时的操作, 然而还是ANR了. 这就有可能是如下两种情况了:

    2.2.2 CPU满负荷

    这个时候你看到的trace信息可能会包含这样的信息:

    Process:com.anly.githubapp
    ...
    CPU usage from 3330ms to 814ms ago:
    6% 178/system_server: 3.5% user + 1.4% kernel / faults: 86 minor 20 major
    4.6% 2976/com.anly.githubapp: 0.7% user + 3.7% kernel /faults: 52 minor 19 major
    0.9% 252/com.android.systemui: 0.9% user + 0% kernel
    ...
    
    100%TOTAL: 5.9% user + 4.1% kernel + 89% iowait
    

    最后一句表明了:

    1. 当是CPU占用100%, 满负荷了.
    2. 其中绝大数是被iowait即I/O操作占用了.

    此时分析方法调用栈, 一般来说会发现是方法中有频繁的文件读写或是数据库读写操作放在主线程来做了.

    2.2.3 内存原因

    其实内存原因有可能会导致ANR, 例如如果由于内存泄露, App可使用内存所剩无几, 我们点击按钮启动一个大图片作为背景的activity, 就可能会产生ANR, 这时trace信息可能是这样的:

    // 以下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的内存已所剩无几.

    当然这种情况可能更多的是会产生OOM的异常...

    2.2 ANR的处理

    针对三种不同的情况, 一般的处理情况如下

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

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

    3. 内存不够用的
      增大VM内存, 使用largeHeap属性, 排查内存泄露(这个在内存优化那篇细说吧)等.

    3, 深入一点

    没有人愿意在出问题之后去解决问题.
    高手和新手的区别是, 高手知道怎么在一开始就避免问题的发生. 那么针对ANR这个问题, 我们需要做哪些层次的工作来避免其发生呢?

    3.1 哪些地方是执行在主线程的

    1. Activity的所有生命周期回调都是执行在主线程的.
    2. Service默认是执行在主线程的.
    3. BroadcastReceiver的onReceive回调是执行在主线程的.
    4. 没有使用子线程的looper的Handler的handleMessage, post(Runnable)是执行在主线程的.
    5. AsyncTask的回调中除了doInBackground, 其他都是执行在主线程的.
    6. View的post(Runnable)是执行在主线程的.

    3.2 使用子线程的方式有哪些

    上面我们几乎一直在说, 避免ANR的方法就是在子线程中执行耗时阻塞操作. 那么在Android中有哪些方式可以让我们实现这一点呢.

    3.2.1 启Thread方式

    这个其实也是Java实现多线程的方式. 有两种实现方法, 继承Thread 或 实现Runnable接口:

    继承Thread

    class PrimeThread extends Thread {
        long minPrime;
        PrimeThread(long minPrime) {
            this.minPrime = minPrime;
        }
    
        public void run() {
            // compute primes larger than minPrime
             . . .
        }
    }
    
    PrimeThread p = new PrimeThread(143);
    p.start();
    

    实现Runnable接口

    class PrimeRun implements Runnable {
        long minPrime;
        PrimeRun(long minPrime) {
            this.minPrime = minPrime;
        }
    
        public void run() {
            // compute primes larger than minPrime
             . . .
        }
    }
    
    PrimeRun p = new PrimeRun(143);
    new Thread(p).start();
    

    3.2.2 使用AsyncTask

    这个是Android特有的方式, AsyncTask顾名思义, 就是异步任务的意思.

    private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
        // Do the long-running work in here
        // 执行在子线程
        protected Long doInBackground(URL... urls) {
            int count = urls.length;
            long totalSize = 0;
            for (int i = 0; i < count; i++) {
                totalSize += Downloader.downloadFile(urls[i]);
                publishProgress((int) ((i / (float) count) * 100));
                // Escape early if cancel() is called
                if (isCancelled()) break;
            }
            return totalSize;
        }
    
        // This is called each time you call publishProgress()
        // 执行在主线程
        protected void onProgressUpdate(Integer... progress) {
            setProgressPercent(progress[0]);
        }
    
        // This is called when doInBackground() is finished
        // 执行在主线程
        protected void onPostExecute(Long result) {
            showNotification("Downloaded " + result + " bytes");
        }
    }
    
    // 启动方式
    new DownloadFilesTask().execute(url1, url2, url3);
    

    3.2.3 HandlerThread

    Android中结合Handler和Thread的一种方式. 前面有云, 默认情况下Handler的handleMessage是执行在主线程的, 但是如果我给这个Handler传入了子线程的looper, handleMessage就会执行在这个子线程中的. HandlerThread正是这样的一个结合体:

    // 启动一个名为new_thread的子线程
    HandlerThread thread = new HandlerThread("new_thread");
    thread.start();
    
    // 取new_thread赋值给ServiceHandler
    private ServiceHandler mServiceHandler;
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
    
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
          super(looper);
        }
        
        @Override
        public void handleMessage(Message msg) {
          // 此时handleMessage是运行在new_thread这个子线程中了.
        }
    }
    

    3.2.4 IntentService

    Service是运行在主线程的, 然而IntentService是运行在子线程的.
    实际上IntentService就是实现了一个HandlerThread + ServiceHandler的模式.

    以上HandlerThread的使用代码示例也就来自于IntentService源码.

    3.2.5 Loader

    Android 3.0引入的数据加载器, 可以在Activity/Fragment中使用. 支持异步加载数据, 并可监控数据源在数据发生变化时传递新结果. 常用的有CursorLoader, 用来加载数据库数据.

    // Prepare the loader.  Either re-connect with an existing one,
    // or start a new one.
    // 使用LoaderManager来初始化Loader
    getLoaderManager().initLoader(0, null, this);
    
    //如果 ID 指定的加载器已存在,则将重复使用上次创建的加载器。
    //如果 ID 指定的加载器不存在,则 initLoader() 将触发 LoaderManager.LoaderCallbacks 方法 //onCreateLoader()。在此方法中,您可以实现代码以实例化并返回新加载器
    
    // 创建一个Loader
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        // This is called when a new Loader needs to be created.  This
        // sample only has one Loader, so we don't care about the ID.
        // First, pick the base URI to use depending on whether we are
        // currently filtering.
        Uri baseUri;
        if (mCurFilter != null) {
            baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
                      Uri.encode(mCurFilter));
        } else {
            baseUri = Contacts.CONTENT_URI;
        }
    
        // Now create and return a CursorLoader that will take care of
        // creating a Cursor for the data being displayed.
        String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
                + Contacts.HAS_PHONE_NUMBER + "=1) AND ("
                + Contacts.DISPLAY_NAME + " != '' ))";
        return new CursorLoader(getActivity(), baseUri,
                CONTACTS_SUMMARY_PROJECTION, select, null,
                Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
    }
    
    // 加载完成
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        // Swap the new cursor in.  (The framework will take care of closing the
        // old cursor once we return.)
        mAdapter.swapCursor(data);
    }
    

     

    3.2.6 特别注意

    使用Thread和HandlerThread时, 为了使效果更好, 建议设置Thread的优先级偏低一点:

    Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND);
    

    因为如果没有做任何优先级设置的话, 你创建的Thread默认和UI Thread是具有同样的优先级的, 你懂的. 同样的优先级的Thread, CPU调度上还是可能会阻塞掉你的UI Thread, 导致ANR的.

    展开全文
  • Android的ANR处理

    2017-05-08 17:08:48
    一:什么是ANR ANR:Application Not Responding,即应用无响应 二:ANR的类型 ANR一般有三种类型: 1:KeyDispatchTimeout(5 seconds) --主要类型 按键或触摸事件在特定时间内无响应 2:Broadcast...
  • SharedPreferences anr 处理方案

    千次阅读 2018-12-08 16:33:58
    SharedPreferences anr 原因以及避免方案 技术背景: AuthMode 和SDK 使用了系统默认的 SharedPreferences,系统的 SharedPreferences 实现类在 android/app/SharedPrefenencesImpl.java 中。 SharedPrefenences 工作...
  • Input ANR处理流程

    2019-02-15 10:15:44
    ANR时间区别便是指当前这次的事件dispatch过程中执行findFocusedWindowTargetsLocked()方法到下一次执行resetANRTimeoutsLocked()的时间区间. 以下5个时机会reset. 都位于InputDispatcher.cpp文件: ...
  • android ANR处理方法

    2011-08-23 10:02:00
    应用程序响应不够灵敏的地方包括——反映迟钝,挂起或冻结很长时间,或者需要花费很长的时间来处理输入。 在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作...
  • ANR处理及Log查看

    2012-06-05 08:23:49
    – 主线程 (“事件处理线程” / “UI线程”) 在5秒内没有响应输入事件 – BroadcastReceiver 没有在10秒内完成返回 通常情况下,下面这些做法会导致ANR 1、在主线程内进行网络操作 2、在主线

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,514
精华内容 605
关键字:

anr处理