【騰訊bugly乾貨分享】精神哥手把手教你怎樣智鬥ANR

上帝說要有ANR,因而Bugly就有了ANR上報。那麼ANR到底是什麼?java

近期很是多童鞋問起精神哥ANR的問題,那麼此次就來聊一下,雞爪怎麼泡纔好吃。噢不,是怎樣高速定位ANR。數據庫

ANR是什麼

簡單說,一般就是App執行的時候,duang~卡住了。怎麼搞都動不了。安全

當卡住超過必定時間。Android系統以爲這就是一次「ANR(Application Not Responding)」。網絡

詳細說。在下面狀況發生時,會發生ANR(可能在不一樣ROM 中時間有所更改):app

  • 用戶的輸入在5s內沒被App響應。函數

  • BroadcastReceiver的onReceiver()超過10s;性能

  • Service中各生命週期函數運行超過20s。動畫


ANR必須死

用戶在App的絕大部分操做,都需要有App的主動迴應。比方按下button以後button樣式的改變、下拉滾動欄內容的移動、載入資源時的菊花轉轉轉,它們都是「操做-反饋」配對的模式。對於咱們手機上最多見的觸摸操做。0.1s的響應延遲已經有很是明顯的卡頓感了。而對於常見的ANR。用戶至少要等5s以上!ui

發生了ANR,每每會彈出對話框,問用戶是繼續等待仍是直接關掉:spa


相信差點兒所有Android手機用戶都見過這個然並卵的ANR對話框,但大部分普通用戶根本不知道這個對話框在講什麼,並且每每也僅僅有關閉App。

漫長的等待就給我看這個?從用戶的體驗看,就是心中一萬僅僅草泥馬奔騰起來撞火車的感覺。可見ANR對於應用的影響並不亞於Crash。

通常來講,界面相對越不「流暢」的App(說明UI線程耗時操做多)越easy發生ANR(一個輸入事件在某個設備A上4秒有了反饋。並不意味着它在其它設備B上是安全的)。

ANR事實上就是界面卡頓的極端狀況。反過來,僅僅要經過合理的方案消滅了App出現的ANR,每每也同一時候會使App展現界面表現會更加順滑流暢。

一些典型的ANR 問題場景

這裏舉幾個easy發生ANR的場景:

1)最多見的錯誤,UI線程等待其餘線程釋放某個鎖,致使UI線程沒法處理用戶輸入。

2)遊戲中每幀動畫都進行了比較耗時的大量計算,致使CPU忙只是來;

3)Web應用中。網絡狀態不穩定。而界面在等待網絡數據;

4)UI線程中進行了一些磁盤IO(包含數據庫、SD卡等等)的操做。在個別設備上因爲硬件損壞等緣由堵塞住了;

5)手機被其它App佔用着CPU。本身獲取不到足夠的CPU 時間片,純屬誤傷。


經過ANR 日誌定位問題

當ANR發生時。咱們每每經過Logcat和traces文件(文件夾/data/anr/)的相關信息輸出去定位問題。主要包括下面幾方面:

1)基本信息,包含進程名、進程號、包名、系統build號、ANR 類型等等;

2)CPU使用信息。包含活躍進程的CPU 平均佔用率、IO狀況等等。

3)線程堆棧信息。所屬進程包含發生ANR的進程、其父進程、近期有活動的3個進程等等。

這裏舉個簡單的樣例(實際上因爲各App所處環境各異,可能出現各類各樣複雜的ANR狀況)當App執行卡住,彈出ANR對話框。查看Logcat輸出:

ActivityManager: ANR in com.tencent.bugly.demo (com.tencent.bugly.demo/.MainActivity)
ActivityManager: PID: 18617
ActivityManager: Reason: Input dispatching timed out (Waiting because the touched window has not finished processing the input events that were previously delivered to it.)
ActivityManager: Load: 18.42 / 18.09 / 18.29
ActivityManager: CPU usage from 5924ms to 475ms ago:
ActivityManager: 93% 18617/com.tencent.bugly.demo: 93% user + 0% kernel / faults: 75 minor
……
ActivityManager: CPU usage from 2906ms to 3429ms later:
ActivityManager: 96% 18617/com.tencent.bugly.demo: 96% user + 0% kernel
……
ActivityManager: 55% TOTAL: 51% user + 3.8% kernel

分析一下,從Logcat可以獲得下面信息:

  1. com.tencent.bugly.demo這個App的MainActivity發生了ANR,進程號18617;

  2. ANR緣由:用戶輸入超時。

  3. ANR發生前、後一段時間分別附在狀況:在ANR發生先後,CPU有90+%耗費在這個demo上,說明很是多是這個demo自身性能引發的。

接下來再看traces文件確認:

----- pid 18617 at xxxx -----
Cmd line: com.tencent.bugly.demo
JNI: CheckJNI is off; workarounds are off; pins=0; globals=272 (plus 2 weak)
DALVIK THREADS:
"main" prio=5 tid=1 SUSPENDED
| group="main" sCount=1 dsCount=0 obj=0x415e4e58 self=0x415d3028
| sysTid=18617 nice=0 sched=0/0 cgrp=apps handle=1074372948
| state=S schedstat=( 38588000572 591063492 5767 ) utm=3846 stm=12 core=0
at com.tencent.bugly.demo.MainActivity$3.doCalc(MainActivity.java:~38)
at com.tencent.bugly.demo.MainActivity$3.onClick(MainActivity.java:33)
……

分析一下,traces文件裏包括下面信息:

一、進程號:18617;包名:com.tencent.bugly.demo。

二、發生ANR時,main線程被掛起(也多是其它等待狀態,比方TIMED_WAIT);

三、線程的幾個重要參數:

  • group:線程組名稱「main」;

  • sCount:Suspended個數「1」。

  • obj:線程的Java對象地址。

  • self:線程的Native對象地址;

  • sysTid:線程號(這裏主線程的線程號=進程號)「18617」。

四、詳細堆棧:從堆棧可以很是清晰看出是doCalc()方法出的問題,由onClick觸發。

綜合以上分析。問題還原爲:com.tencent.bugly.demo這個App的MainActivity中有個耗時的doCalc方法在跑。沒法響應用戶的觸摸或按鍵輸入。OK。接下來在代碼裏找問題就行了。

怎樣解決ANR

固然是儘量下降UI線程的耗時操做。以及BroadcastReceiver、Service生命週期中的標準回調方法啦。

Android官方文檔建議:

1)使用AsyncTask類,可以很是方便地實現子線程耗時操做與UI更新;

2)對於BroadcastReceiver的耗時操做。建議放到Service中運行。

3)對於自建的Thread,可以經過Handler使之與UI 線程通訊(這裏需要注意的是。Thread默認優先級和UI線程是同樣的,建議設置通常線程優先級爲Process.THREAD_PRIORITY_BACKGROUND)。

這些方案你們應該都知道。只是仍不免有大量的ANR是寫代碼時忽略了,在測試時沒發生,終於在用戶的手機上出現的。回憶一下是否是都經歷過用戶會反饋「App卡死沒反應了」。但開發GG客服MM們卻又因爲缺乏日誌或沒法復現而一籌莫展?所以要修復ANR。首先是要能發現用戶ANR了。並且能知道是哪段代碼致使ANR了,這樣才幹談修復。


爲了幫助廣大開發人員解決這一難題,騰訊Bugly針對iOS的卡頓及Android的ANR提供監測服務即將上線,協助開發人員輕鬆定位問題。

相關文章
相關標籤/搜索