Android ANR:原理分析及解決辦法

目錄:
一、ANR說明和原因
二彩届、ANR分析辦法
三、如何降低ANR的概率
四奖唯、造成ANR的原因及解決辦法
五惨缆、ANR源碼分析
六、Android ANR的信息收集

一、ANR說明和原因

1.1 簡介

ANR全稱:Application Not Responding坯墨,也就是應(yīng)用程序無響應(yīng)寂汇。

1.2 原因

Android系統(tǒng)中,ActivityManagerService(簡稱AMS)和WindowManagerService(簡稱WMS)會檢測App的響應(yīng)時間捣染,如果App在特定時間無法響應(yīng)屏幕觸摸或鍵盤輸入時間骄瓣,或者特定事件沒有處理完畢,就會出現(xiàn)ANR耍攘。

以下四個條件都可以造成ANR發(fā)生:

  • InputDispatching Timeout:5秒內(nèi)無法響應(yīng)屏幕觸摸事件或鍵盤輸入事件

  • BroadcastQueue Timeout :在執(zhí)行前臺廣播(BroadcastReceiver)的onReceive()函數(shù)時10秒沒有處理完成榕栏,后臺為60秒。

  • Service Timeout :Service的各個生命周期函數(shù)在特定時間內(nèi)(前臺服務(wù)20s,后臺服務(wù)200s)無法完成響應(yīng)蕾各。

  • ContentProvider Timeout :ContentProvider的publish在10s內(nèi)沒進(jìn)行完扒磁。
    (進(jìn)程啟動過程中,如果發(fā)生會直接殺進(jìn)程以及清理相應(yīng)信息,而不會彈出ANR的對話框)

1.3 避免

盡量避免在主線程(UI線程)中作耗時操作式曲。

那么耗時操作就放在子線程中妨托。

關(guān)于多線程可以參考:Android多線程:理解和簡單使用總結(jié)

二、ANR分析辦法

從前文可以明確吝羞,ANR問題是由于主線程的任務(wù)在規(guī)定時間內(nèi)沒處理完任務(wù)兰伤,而造成這種情況的原因大致會有一下幾點(diǎn):

  1. 主線程在做一些耗時的工作

  2. 主線程被其他線程鎖

  3. cpu被其他進(jìn)程占用,該進(jìn)程沒被分配到足夠的cpu資源钧排。

判斷一個ANR屬于哪種情況便是分析ANR問題的關(guān)鍵敦腔。那么拿到一個anr的日志,應(yīng)該如何分析呢恨溜?

在發(fā)生ANR的時候符衔,系統(tǒng)會收集ANR相關(guān)的信息提供給開發(fā)者:首先在Log中有ANR相關(guān)的信息,其次會收集ANR時的CPU使用情況筒捺,還會收集trace信息柏腻,也就是當(dāng)時各個線程的執(zhí)行情況纸厉。trace文件保存到了/data/anr/traces.txt中系吭,此外,ANR前后該進(jìn)程打印出的log也有一定價值颗品。一般來說可以按一下思路來分析:

  1. 從log中找到ANR反生的信息:可以從log中搜索“ANR in”或“am_anr”肯尺,會找到ANR發(fā)生的log,該行會包含了ANR的時間躯枢、進(jìn)程则吟、是何種ANR等信息,如果是BroadcastReceiver的ANR可以懷疑BroadCastReceiver.onRecieve()的問題锄蹂,如果的Service或Provider就懷疑是否其onCreate()的問題氓仲。

  2. 在該條log之后會有CPU usage的信息,表明了CPU在ANR前后的用量(log會表明截取ANR的時間),從各種CPU Usage信息中大概可以分析如下幾點(diǎn):

    (1). 如果某些進(jìn)程的CPU占用百分比較高敬扛,幾乎占用了所有CPU資源晰洒,而發(fā)生ANR的進(jìn)程CPU占用為0%或非常低,則認(rèn)為CPU資源被占用啥箭,進(jìn)程沒有被分配足夠的資源谍珊,從而發(fā)生了ANR。這種情況多數(shù)可以認(rèn)為是系統(tǒng)狀態(tài)的問題急侥,并不是由本應(yīng)用造成的砌滞。

    (2). 如果發(fā)生ANR的進(jìn)程CPU占用較高,如到了80%或90%以上坏怪,則可以懷疑應(yīng)用內(nèi)一些代碼不合理消耗掉了CPU資源贝润,如出現(xiàn)了死循環(huán)或者后臺有許多線程執(zhí)行任務(wù)等等原因,這就要結(jié)合trace和ANR前后的log進(jìn)一步分析了铝宵。

    (3). 如果CPU總用量不高题暖,該進(jìn)程和其他進(jìn)程的占用過高,這有一定概率是由于某些主線程的操作就是耗時過長捉超,或者是由于主進(jìn)程被鎖造成的胧卤。

  3. 除了上述的情況(1)以外,分析CPU usage之后拼岳,確定問題需要我們進(jìn)一步分析trace文件枝誊。trace文件記錄了發(fā)生ANR前后該進(jìn)程的各個線程的stack。對我們分析ANR問題最有價值的就是其中主線程的stack惜纸,一般主線程的trace可能有如下幾種情況:

    (1). 主線程是running或者native而對應(yīng)的棧對應(yīng)了我們應(yīng)用中的函數(shù)叶撒,則很有可能就是執(zhí)行該函數(shù)時候發(fā)生了超時。

    (2). 主線程被block:非常明顯的線程被鎖耐版,這時候可以看是被哪個線程鎖了祠够,可以考慮優(yōu)化代碼。如果是死鎖問題粪牲,就更需要及時解決了古瓤。

    (3). 由于抓trace的時刻很有可能耗時操作已經(jīng)執(zhí)行完了(ANR -> 耗時操作執(zhí)行完畢 ->系統(tǒng)抓trace),這時候的trace就沒有什么用了腺阳,主線程的stack就是這樣的:


    16ad355cb45639f5.png

三落君、如何降低ANR的概率

有一些操作是很危險的,非常容易發(fā)生ANR亭引,在寫代碼時候一定要避免:

  1. 主線程讀取數(shù)據(jù):在Android中主線程去讀取數(shù)據(jù)是非常不好的绎速,Android是不允許主線程從網(wǎng)絡(luò)讀數(shù)據(jù)的,但系統(tǒng)允許主線程從數(shù)據(jù)庫或者其他地方獲取數(shù)據(jù)焙蚓,但這種操作ANR風(fēng)險很大纹冤,也會造成掉幀等洒宝,影響用戶體驗。

    (1)避免在主線程query provider萌京,首先這會比較耗時待德,另外這個操作provider那一方的進(jìn)程如果掛掉了或者正在啟動,我們應(yīng)用的query就會很長時間不會返回枫夺,我們應(yīng)該在其他線程中執(zhí)行數(shù)據(jù)庫query将宪、provider的query等獲取數(shù)據(jù)的操作。

    (2)sharePreference的調(diào)用:針對sharePreference的優(yōu)化點(diǎn)有很多橡庞,文章http://weishu.me/2016/10/13/sharedpreference-advices/ 詳細(xì)介紹了幾點(diǎn)sharepreference使用時候的注意事項较坛。首先sharePreference的commit()方法是同步的,apply()方法一般是異步執(zhí)行的扒最。所以在主線程不要用其commit()丑勤,用apply()替換。其次sharePreference的寫是全量寫而非增量寫吧趣,所以盡量都修改完同一apply法竞,避免改一點(diǎn)apply一次(apply()方法在Activity stop的時候主線程會等待寫入完成,提交多次就很容易卡)强挫。并且存儲文本也不宜過大岔霸,這樣會很慢。另外俯渤,如果寫入的是json或者xml呆细,由于需要加和刪轉(zhuǎn)義符號,速度會比較慢八匠。

  2. 不要在broadcastReciever的onRecieve()方法中干活絮爷,這一點(diǎn)很容易被忽略,尤其應(yīng)用在后臺的時候梨树。為避免這種情況坑夯,一種解決方案是直接開的異步線程執(zhí)行,但此時應(yīng)用可能在后臺抡四,系統(tǒng)優(yōu)先級較低柜蜈,進(jìn)程很容易被系統(tǒng)殺死,所以可以選擇開個IntentService去執(zhí)行相應(yīng)操作床嫌,即使是后臺Service也會提高進(jìn)程優(yōu)先級跨释,降低被殺可能性。

  3. 各個組件的生命周期函數(shù)都不應(yīng)該有太耗時的操作厌处,即使對于后臺Service或者ContentProvider來講,應(yīng)用在后臺運(yùn)行時候其onCreate()時候不會有用戶輸入引起事件無響應(yīng)ANR岁疼,但其執(zhí)行時間過長也會引起Service的ANR和ContentProvider的ANR阔涉。

  4. 盡量避免主線程的被鎖的情況缆娃,在一些同步的操作主線程有可能被鎖,需要等待其他線程釋放相應(yīng)鎖才能繼續(xù)執(zhí)行瑰排,這樣會有一定的ANR風(fēng)險贯要,對于這種情況有時也可以用異步線程來執(zhí)行相應(yīng)的邏輯。另外椭住, 我們要避免死鎖的發(fā)生(主線程被死鎖基本就等于要發(fā)生ANR了)崇渗。

四、造成ANR的原因及解決辦法

上面例子只是由于簡單的主線程耗時操作造成的ANR京郑,造成ANR的原因還有很多:

  • 主線程阻塞或主線程數(shù)據(jù)讀取

解決辦法:避免死鎖的出現(xiàn)宅广,使用子線程來處理耗時操作或阻塞任務(wù)。盡量避免在主線程query provider些举、不要濫用SharePreferenceS

  • CPU滿負(fù)荷跟狱,I/O阻塞

解決辦法:文件讀寫或數(shù)據(jù)庫操作放在子線程異步操作。

  • 內(nèi)存不足

解決辦法:AndroidManifest.xml文件<applicatiion>中可以設(shè)置 android:largeHeap="true"户魏,以此增大App使用內(nèi)存驶臊。不過不建議使用此法,從根本上防止內(nèi)存泄漏叼丑,優(yōu)化內(nèi)存使用才是正道关翎。

  • 各大組件ANR

各大組件生命周期中也應(yīng)避免耗時操作,注意BroadcastReciever的onRecieve()鸠信、后臺Service和ContentProvider也不要執(zhí)行太長時間的任務(wù)笤休。

五、ANR源碼分析

特別聲明:文章 理解Android ANR的觸發(fā)原理 分別記錄了由Service症副、BroadcastReceiver和ContentProvider造成的ANR店雅。下文引用該文代碼,并依據(jù)自己的簡單理解作總結(jié)贞铣。

http://www.reibang.com/p/388166988cef

六闹啦、Android ANR的信息收集

無論是四大組件或者進(jìn)程等只要發(fā)生ANR,最終都會調(diào)用AMS.appNotResponding()方法辕坝。

參考:理解Android ANR的信息收集過程

參考網(wǎng)址 :
Android ANR問題總結(jié)
Android ANR:原理分析及解決辦法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末窍奋,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子酱畅,更是在濱河造成了極大的恐慌琳袄,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纺酸,死亡現(xiàn)場離奇詭異窖逗,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)餐蔬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門碎紊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來佑附,“玉大人,你說我怎么就攤上這事仗考∫敉” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵秃嗜,是天一觀的道長权均。 經(jīng)常有香客問我,道長锅锨,這世上最難降的妖魔是什么叽赊? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮橡类,結(jié)果婚禮上蛇尚,老公的妹妹穿的比我還像新娘。我一直安慰自己顾画,他們只是感情好取劫,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著研侣,像睡著了一般谱邪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上庶诡,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天惦银,我揣著相機(jī)與錄音,去河邊找鬼末誓。 笑死扯俱,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的喇澡。 我是一名探鬼主播迅栅,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼晴玖!你這毒婦竟也來了读存?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤呕屎,失蹤者是張志新(化名)和其女友劉穎让簿,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秀睛,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡尔当,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了琅催。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片居凶。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡虫给,死狀恐怖藤抡,靈堂內(nèi)的尸體忽然破棺而出侠碧,到底是詐尸還是另有隱情,我是刑警寧澤缠黍,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布弄兜,位于F島的核電站,受9級特大地震影響瓷式,放射性物質(zhì)發(fā)生泄漏替饿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一贸典、第九天 我趴在偏房一處隱蔽的房頂上張望视卢。 院中可真熱鬧,春花似錦廊驼、人聲如沸据过。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绳锅。三九已至,卻和暖如春酝掩,著一層夾襖步出監(jiān)牢的瞬間鳞芙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工期虾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留原朝,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓镶苞,卻偏偏與公主長得像喳坠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子宾尚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345