分析Android中的ANR

什麼是ANR

Application Not Responding,意思就是程序未響應。

如果一個應用無法響應用戶的輸入,系統就會彈出一個ANR對話框,如下圖所示:

這裏寫圖片描述

用戶可以自行選擇繼續等待,或者是停止當前程序。

ANR產生的條件

只有主線程纔會產生ANR

在Activity中5s無響應,在BroadcastReceiver中10s無響應,在Service中20s無響應。

ANR產生的根本原因

1.CPU被佔用導致主線程得不到CPU的資源,比如其他線程在進行頻繁的讀寫操作。

2.在主線程中執行了耗時操作,比如在主線程中進行數據庫操作或者訪問網絡。

分析ANR

導出ANR文件

ANR產生時, 系統會生成一個traces.txt的文件放在data/anr/下。可以通過adb命令將其導出到本地,例如:

adb pull /data/anr/traces.txt D:/tingshuonitiao

D:/tingshuonitiao是接收導出文件的本地文件夾。

分析ANR文件

1.耗時操作導致的ANR

----- pid 7710 at 2017-10-25 01:24:53 -----  //發生ANR的時間
Cmd line: com.tsnt.relax  //最新ANR發生的進程
Build fingerprint: 'Android/sdk_google_phone_x86/generic_x86:6.0/MASTER/3079352:userdebug/test-keys'
ABI: 'x86'
……
DALVIK THREADS (16):
……
"main" prio=5 tid=1 Sleeping
  | group="main" sCount=1 dsCount=0 obj=0x73d99f68 self=0xb4134500
  | sysTid=7710 nice=0 cgrp=default sched=0/0 handle=0xb77f7c00
  | state=S schedstat=( 0 0 0 ) utm=9 stm=18 core=1 HZ=100
  | stack=0xbf144000-0xbf146000 stackSize=8MB
  | held mutexes=
  at java.lang.Thread.sleep!(Native method)
  - sleeping on <0x07abb553> (a java.lang.Object)
  at java.lang.Thread.sleep(Thread.java:1031)
  - locked <0x07abb553> (a java.lang.Object)
  at java.lang.Thread.sleep(Thread.java:985)
  at android.os.SystemClock.sleep(SystemClock.java:120)
  at com.tsnt.relax.fragment.SceneFragment$3.onClick(SceneFragment.java:100)  //程序中出現ANR的地方
  at android.view.View.performClick(View.java:5198)
  at android.view.View$PerformClick.run(View.java:21147)
  at android.os.Handler.handleCallback(Handler.java:739)
  at android.os.Handler.dispatchMessage(Handler.java:95)
  at android.os.Looper.loop(Looper.java:148)
  at android.app.ActivityThread.main(ActivityThread.java:5417)
  at java.lang.reflect.Method.invoke!(Native method)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

我們來看到程序中SceneFragment的部分代碼:

        mTitle.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SystemClock.sleep(6000);
                mPopupWindow.showAsDropDown(mToolbar);
            }
        });

原因很明顯,在主線程中做了耗時操作

2.CPU被佔用導致的ANR

這個時候你看到的trace信息可能會包含這樣的信息:

Process:com.tsnt.relax
……
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

其中最後一句表明:CPU佔用達到100%,並且其中絕大數是被iowait即I/O操作佔用了。

從各種CPU Usage信息中大概可以分析如下幾種情況:

  • 如果某些其他進程的CPU佔用較高,幾乎佔用了所有CPU資源,而發生ANR的進程CPU佔用爲0%或非常低,則認爲CPU資源被佔用,進程沒有被分配足夠的資源,從而發生了ANR。這種情況多數可以認爲是系統狀態的問題,並不是由本應用造成的。

  • 如果發生ANR的進程CPU佔用較高,如到了80%或90%以上,則可以懷疑應用內一些代碼不合理消耗掉了CPU資源,如出現了死循環或者後臺有許多線程執行任務等等原因,這就要結合trace和ANR前後的log進一步分析了。

  • 如果CPU總用量不高,這有一定概率是由於主線程的操作耗時過長,或者是由於主進程被鎖。

3.內存原因導致的ANR

其實內存原因也有可能會導致ANR,假設App可使用內存不多時我們加載一個大圖片,就可能會產生ANR,這時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。

ANR機制的實現原理

請參考gityuan的博客

如何降低ANR的概率

1.主線程中不要進行耗時操作,把耗時操作放在子線程中。

2.儘量避免主線程的被鎖的情況

3.避免應用內的I/O密集型操作

參考:
1.[轉]Android ANR 分析解決方法
2.Android App優化之ANR詳解
3.android ANR發生的原因總結和解決辦法
4.Android ANR問題總結

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章