99%面試必問(wèn)題目:講一下ANR吧争群!

1.什么是ANR

ANR(Application Not responding)是指應(yīng)用程序未響應(yīng)课梳,主線程如果在規(guī)定時(shí)間內(nèi)沒(méi)有處理完相應(yīng)的工作理卑,就會(huì)出現(xiàn)ANR翘紊,ANR本質(zhì)上是性能問(wèn)題,ANR機(jī)制實(shí)際上是對(duì)應(yīng)用程序的主線程起到了限制作用藐唠。

2.ANR產(chǎn)生的原因是什么帆疟?

主線程(UI線程)如果在規(guī)定時(shí)間內(nèi)沒(méi)有處理完相應(yīng)的工作鹉究,就會(huì)出現(xiàn)ANR,具體的說(shuō)就是:

1. 輸入事件(按鍵和觸摸事件)5s內(nèi)沒(méi)有被處理:Input event dispatching timed out
2. BroadcaseReceiver的事件(onReceive方法)在規(guī)定時(shí)間內(nèi)沒(méi)處理完(前臺(tái)廣播10s,后臺(tái)廣播60s):Timeout of broadcast BroadcastRecord
3. service前臺(tái)20s,后臺(tái)200s沒(méi)有完成啟動(dòng) :Timeout executing service
4. ContentProvider的publish在10s內(nèi)沒(méi)進(jìn)行完:Timeout publishing content providers

3.ANR發(fā)生的原理 -- 機(jī)制

ANR機(jī)制可以分為兩部分:

  • ANR監(jiān)測(cè)機(jī)制:Android對(duì)于不同的ANR類型(Broadcast, Service, InputEvent)都有一套監(jiān)測(cè)機(jī)制踪宠。
  • ANR報(bào)告機(jī)制:在監(jiān)測(cè)到ANR以后自赔,需要顯示ANR對(duì)話框、輸出日志(發(fā)生ANR時(shí)的進(jìn)程函數(shù)調(diào)用棧柳琢、CPU使用情況等)绍妨。

整個(gè)ANR機(jī)制的代碼也是橫跨了Android的幾個(gè)層:

  • App層:應(yīng)用主線程的處理邏輯;
  • Framework層:ANR機(jī)制的核心柬脸,主要有AMS他去、BroadcastQueue、ActiveServices倒堕、InputmanagerService灾测、InputMonitor、InputChannel垦巴、ProcessCpuTracker等媳搪;
  • Native層:InputDispatcher.cpp;

直白的說(shuō)就是程序在執(zhí)行相關(guān)操作的時(shí)候骤宣,會(huì)通過(guò)handler發(fā)送一個(gè)延時(shí)消息秦爆,也就是ANR消息,延時(shí)的時(shí)間就是不同組件發(fā)生ANR的時(shí)間涯雅,當(dāng)我們進(jìn)行相關(guān)操作之后鲜结,會(huì)romove掉該條message,如果相關(guān)的操作沒(méi)有在規(guī)定的時(shí)間內(nèi)完成活逆,那么Handler就會(huì)執(zhí)行該條message精刷,就發(fā)生的ANR。

4.ANR定位 - 如何找到ANR發(fā)生的原因

發(fā)生ANR的原因有以下幾點(diǎn):

  1. 主線程在做一些耗時(shí)任務(wù)
  2. 主線程被其他線程鎖
  3. cpu被其他進(jìn)程占用蔗候,該進(jìn)程沒(méi)被分配到足夠的cpu資源

如何準(zhǔn)確的找到ANR發(fā)生的位置怒允,就需要我們結(jié)合具體的場(chǎng)景進(jìn)行分析,具體可以從以下幾個(gè)方面進(jìn)行分析

  1. 可以在log中搜索“ANR in”或“am_anr”锈遥,會(huì)找到ANR發(fā)生的log纫事,該行會(huì)包含了ANR的時(shí)間、進(jìn)程所灸、是何種ANR等信息丽惶,如果是BroadcastReceiver的ANR,可以懷疑是BroadcastReceiver.onReceive()方法的問(wèn)題爬立。如果是Service或Provider就懷疑是否其onCreate()的問(wèn)題钾唬。

  2. 在該條log之后會(huì)有CPU usage的信息,表明了CPU在ANR前后的用量(log會(huì)表明截取ANR的時(shí)間),從各種CPU Usage信息中大概可以分析如下幾點(diǎn):
    (1). 如果某些進(jìn)程的CPU占用百分比較高抡秆,幾乎占用了所有CPU資源奕巍,而發(fā)生ANR的進(jìn)程CPU占用為0%或非常低,則認(rèn)為CPU資源被占用儒士,進(jìn)程沒(méi)有被分配足夠的資源的止,從而發(fā)生了ANR。這種情況多數(shù)可以認(rèn)為是系統(tǒng)狀態(tài)的問(wèn)題着撩,并不是由本應(yīng)用造成的诅福。
    (2). 如果發(fā)生ANR的進(jìn)程CPU占用較高,如到了80%或90%以上拖叙,則可以懷疑應(yīng)用內(nèi)一些代碼不合理消耗掉了CPU資源权谁,如出現(xiàn)了死循環(huán)或者后臺(tái)有許多線程執(zhí)行任務(wù)等等原因,這就要結(jié)合trace和ANR前后的log進(jìn)一步分析了憋沿。
    (3). 如果CPU總用量不高旺芽,該進(jìn)程和其他進(jìn)程的占用過(guò)高,這有一定概率是由于某些主線程的操作就是耗時(shí)過(guò)長(zhǎng)辐啄,或者是由于主進(jìn)程被鎖造成的采章。

  3. 除了上述的情況(1)以外,分析CPU usage之后壶辜,確定問(wèn)題需要我們進(jìn)一步分析trace文件悯舟。trace文件記錄了發(fā)生ANR前后該進(jìn)程的各個(gè)線程的stack。對(duì)我們分析ANR問(wèn)題最有價(jià)值的就是其中主線程的stack砸民,一般主線程的trace可能有如下幾種情況:
    (1). 主線程是running或者native而對(duì)應(yīng)的棧對(duì)應(yīng)了我們應(yīng)用中的函數(shù)抵怎,則很有可能就是執(zhí)行該函數(shù)時(shí)候發(fā)生了超時(shí)。
    (2). 主線程被block:非常明顯的線程被鎖岭参,這時(shí)候可以看是被哪個(gè)線程鎖了反惕,可以考慮優(yōu)化代碼。如果是死鎖問(wèn)題演侯,就更需要及時(shí)解決了姿染。
    (3). 由于抓trace的時(shí)刻很有可能耗時(shí)操作已經(jīng)執(zhí)行完了(ANR -> 耗時(shí)操作執(zhí)行完畢 ->系統(tǒng)抓trace),這時(shí)候的trace就沒(méi)有什么用了秒际,主線程的stack就是這樣的:

"main" prio=5 tid=1 Native
  | group="main" sCount=1 dsCount=0 obj=0x757855c8 self=0xb4d76500
  | sysTid=3276 nice=0 cgrp=default sched=0/0 handle=0xb6ff5b34
  | state=S schedstat=( 50540218363 186568972172 209049 ) utm=3290 stm=1764 core=3 HZ=100
  | stack=0xbe307000-0xbe309000 stackSize=8MB
  | held mutexes=
  kernel: (couldn't read /proc/self/task/3276/stack)
  native: #00 pc 0004099c  /system/lib/libc.so (__epoll_pwait+20)
  native: #01 pc 00019f63  /system/lib/libc.so (epoll_pwait+26)
  native: #02 pc 00019f71  /system/lib/libc.so (epoll_wait+6)
  native: #03 pc 00012ce7  /system/lib/libutils.so (_ZN7android6Looper9pollInnerEi+102)
  native: #04 pc 00012f63  /system/lib/libutils.so (_ZN7android6Looper8pollOnceEiPiS1_PPv+130)
  native: #05 pc 00086abd  /system/lib/libandroid_runtime.so (_ZN7android18NativeMessageQueue8pollOnceEP7_JNIEnvP8_jobjecti+22)
  native: #06 pc 0000055d  /data/dalvik-cache/arm/system@framework@boot.oat (Java_android_os_MessageQueue_nativePollOnce__JI+96)
  at android.os.MessageQueue.nativePollOnce(Native method)
  at android.os.MessageQueue.next(MessageQueue.java:323)
  at android.os.Looper.loop(Looper.java:138)
  at android.app.ActivityThread.main(ActivityThread.java:5528)
  at java.lang.reflect.Method.invoke!(Native method)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:740)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:630)

當(dāng)然這種情況很有可能是由于該進(jìn)程的其他線程消耗掉了CPU資源悬赏,這就需要分析其他線程的trace以及ANR前后該進(jìn)程自己輸出的log了。

5.ANR的修正 - 如何避免ANR

  1. 主線程讀取數(shù)據(jù):在Android中主線程去讀取數(shù)據(jù)是非常不友好的娄徊,Android從2.3之后是不允許主線程從網(wǎng)絡(luò)讀取數(shù)據(jù)的闽颇,但系統(tǒng)允許主線程從數(shù)據(jù)庫(kù)或者其他地方讀取數(shù)據(jù),但是這種情況就會(huì)容易產(chǎn)生ANR寄锐。
    • 避免在主線程執(zhí)行query provider兵多,首先這會(huì)比較耗時(shí)捻脖,另外這個(gè)操作provider那一方如果掛掉的話或者正在啟動(dòng),那我們應(yīng)用的query就會(huì)很長(zhǎng)時(shí)間不會(huì)返回中鼠,我們應(yīng)該在其他線程中執(zhí)行數(shù)據(jù)庫(kù)的query,provider的query等獲取數(shù)據(jù)的操作沿癞。
    • sharePreference的調(diào)用援雇。sharePreference的commit()方法是同步的,apply()方法一般是異步執(zhí)行椎扬。所以在主線程不要用commit()方法惫搏,用apply()替換。SharedPreference的寫(xiě)是全量寫(xiě)而非增量寫(xiě)蚕涤。所以盡量都修改完然后再調(diào)用apply()筐赔,apply()方法再Activity stop的時(shí)候,主線程會(huì)等待寫(xiě)入完成揖铜,提交多次就會(huì)容易造成卡頓茴丰。并且存儲(chǔ)文本不宜過(guò)大,這樣會(huì)很慢天吓。另外贿肩,如果寫(xiě)入的是json或者xml,由于需要加和刪轉(zhuǎn)義符號(hào)龄寞,速度會(huì)比較慢汰规。
  2. 盡量避免在BroadcastReceiver的onReceive()方法中執(zhí)行操作,特別是應(yīng)用在后臺(tái)的時(shí)候物邑,為了避免這種情況溜哮,一種解決方案是直接開(kāi)啟異步線程去執(zhí)行任務(wù),但是此時(shí)應(yīng)用可能在后臺(tái)色解,系統(tǒng)優(yōu)先級(jí)較低茂嗓,進(jìn)程很容易就被殺死了,所以可以選擇開(kāi)啟Service去執(zhí)行任務(wù)科阎。
  3. 各個(gè)組件的生命周期函數(shù)都不應(yīng)該有太耗時(shí)的操作在抛,即使對(duì)于后臺(tái)Service或者ContentProvider來(lái)講,應(yīng)用在后臺(tái)運(yùn)行時(shí)候其onCreate()時(shí)候不會(huì)有用戶輸入引起事件無(wú)響應(yīng)ANR萧恕,但其執(zhí)行時(shí)間過(guò)長(zhǎng)也會(huì)引起Service的ANR和ContentProvider的ANR刚梭。
  4. 盡量避免主線程的被鎖的情況,在一些同步的操作主線程有可能被鎖票唆,需要等待其他線程釋放相應(yīng)鎖才能繼續(xù)執(zhí)行朴读,這樣會(huì)有一定的ANR風(fēng)險(xiǎn),對(duì)于這種情況有時(shí)也可以用異步線程來(lái)執(zhí)行相應(yīng)的邏輯走趋。另外衅金, 我們要避免死鎖的發(fā)生(主線程被死鎖基本就等于要發(fā)生ANR了)。

參考資料
ANR監(jiān)測(cè)機(jī)制
Android ANR問(wèn)題總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市氮唯,隨后出現(xiàn)的幾起案子鉴吹,更是在濱河造成了極大的恐慌,老刑警劉巖惩琉,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件豆励,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡瞒渠,警方通過(guò)查閱死者的電腦和手機(jī)良蒸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)伍玖,“玉大人嫩痰,你說(shuō)我怎么就攤上這事∏瞎浚” “怎么了串纺?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)椰棘。 經(jīng)常有香客問(wèn)我造垛,道長(zhǎng),這世上最難降的妖魔是什么晰搀? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任五辽,我火速辦了婚禮,結(jié)果婚禮上外恕,老公的妹妹穿的比我還像新娘杆逗。我一直安慰自己,他們只是感情好鳞疲,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布罪郊。 她就那樣靜靜地躺著,像睡著了一般尚洽。 火紅的嫁衣襯著肌膚如雪悔橄。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,578評(píng)論 1 305
  • 那天腺毫,我揣著相機(jī)與錄音癣疟,去河邊找鬼。 笑死潮酒,一個(gè)胖子當(dāng)著我的面吹牛睛挚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播急黎,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼扎狱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼侧到!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起淤击,我...
    開(kāi)封第一講書(shū)人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤匠抗,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后污抬,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體汞贸,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年壕吹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片删铃。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡耳贬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出猎唁,到底是詐尸還是另有隱情咒劲,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布诫隅,位于F島的核電站腐魂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏逐纬。R本人自食惡果不足惜蛔屹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望豁生。 院中可真熱鬧兔毒,春花似錦、人聲如沸甸箱。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)芍殖。三九已至豪嗽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間豌骏,已是汗流浹背龟梦。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留窃躲,地道東北人变秦。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像框舔,于是被迫代替她去往敵國(guó)和親蹦玫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赎婚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 面試必背 會(huì)舍棄、總結(jié)概括——根據(jù)我這些年面試和看面試題搜集過(guò)來(lái)的知識(shí)點(diǎn)匯總而來(lái) 建議根據(jù)我的寫(xiě)的面試應(yīng)對(duì)思路中的...
    luoyangzk閱讀 6,755評(píng)論 6 173
  • 在實(shí)際情況中樱溉,當(dāng)Android項(xiàng)目的用戶量特別大時(shí)候挣输,一些細(xì)小的問(wèn)題也會(huì)被放大,ANR問(wèn)題就是一個(gè)典型的例子。一些...
    Uprising閱讀 54,005評(píng)論 4 116
  • ANR問(wèn)題,相信是每位開(kāi)發(fā)日常都會(huì)遇到的問(wèn)題完丽,對(duì)于這類問(wèn)題的分析,按照官方的推薦拇舀,或網(wǎng)絡(luò)博客的總結(jié)思路能解決一定的...
    tiger桂閱讀 17,918評(píng)論 5 28
  • 5月以來(lái)抠璃,哪怕對(duì)市場(chǎng)風(fēng)向再不敏感的人,也感覺(jué)到陣陣涼意脱惰。二級(jí)市場(chǎng)連續(xù)下挫搏嗡,一級(jí)市場(chǎng)融資環(huán)境惡化,不論企業(yè)融資數(shù)量還...
    錢(qián)皓頻道閱讀 6,052評(píng)論 1 6
  • 推薦指數(shù): 6.0 書(shū)籍主旨關(guān)鍵詞:特權(quán)拉一、焦點(diǎn)彻况、注意力、語(yǔ)言聯(lián)想舅踪、情景聯(lián)想 觀點(diǎn): 1.統(tǒng)計(jì)學(xué)現(xiàn)在叫數(shù)據(jù)分析纽甘,社會(huì)...
    Jenaral閱讀 5,721評(píng)論 0 5