摘要:使用或者時(shí),調(diào)用設(shè)置優(yōu)先級(jí),否則仍然會(huì)降低程序響應(yīng),因?yàn)槟J(rèn)的優(yōu)先級(jí)和主線程相同。使用處理工作線程結(jié)果,而不是使用或者來(lái)阻塞主線程。
1.ANR簡(jiǎn)單介紹
2.ANR發(fā)生場(chǎng)景
3.ANR發(fā)生的原理
4.ANR有哪些具體案例
5.ANR具體如何分析
6.解決方案
7.ANR問(wèn)題解答
好消息
博客筆記大匯總【16年3月到至今】,包括Java基礎(chǔ)及深入知識(shí)點(diǎn),Android技術(shù)博客,Python學(xué)習(xí)筆記等等,還包括平時(shí)開(kāi)發(fā)中遇到的bug匯總,當(dāng)然也在工作之余收集了大量的面試題,長(zhǎng)期更新維護(hù)并且修正,持續(xù)完善……開(kāi)源的文件是markdown格式的!同時(shí)也開(kāi)源了生活博客,從12年起,積累共計(jì)47篇[近20萬(wàn)字],轉(zhuǎn)載請(qǐng)注明出處,謝謝!
鏈接地址:github.com/yangchong21…
如果覺(jué)得好,可以star一下,謝謝!當(dāng)然也歡迎提出建議,萬(wàn)事起于忽微,量變引起質(zhì)變!
1.ANR簡(jiǎn)單介紹
1.1 什么是ANR
ANR Activity not responding(頁(yè)面沒(méi)有響應(yīng))
ANR Application not responding 應(yīng)用沒(méi)有響應(yīng)
Android 在4.0之后強(qiáng)制規(guī)定 訪問(wèn)網(wǎng)絡(luò)必須開(kāi)啟子線程
如果在主線程訪問(wèn)網(wǎng)絡(luò),4.0之后的系統(tǒng)就會(huì)拋出:android.os.NetworkOnMainThreadException 在主線程聯(lián)網(wǎng)的異常
聯(lián)網(wǎng)的時(shí)候一定要在子線程操作,只要是耗時(shí)的操作,可能會(huì)把主線程阻塞住的操作,都要放到子線程里
主線程(UI線程)16ms,刷新一次界面,一秒60次,60貞/秒
ANR(Application Not responding),是指應(yīng)用程序未響應(yīng),Android系統(tǒng)對(duì)于一些事件需要在一定的時(shí)間范圍內(nèi)完成,如果超過(guò)預(yù)定時(shí)間能未能得到有效響應(yīng)或者響應(yīng)時(shí)間過(guò)長(zhǎng),都會(huì)造成ANR。
1.2 ANR的產(chǎn)生需要滿足三個(gè)條件
主線程:只有應(yīng)用程序進(jìn)程的主線程響應(yīng)超時(shí)才會(huì)產(chǎn)生ANR;
超時(shí)時(shí)間:產(chǎn)生ANR的上下文不同,超時(shí)時(shí)間也會(huì)不同,但只要在這個(gè)時(shí)間上限內(nèi)沒(méi)有響應(yīng)就會(huì)ANR;
輸入事件/特定操作:輸入事件是指按鍵、觸屏等設(shè)備輸入事件,特定操作是指BroadcastReceiver和Service的生命周期中的各個(gè)函數(shù),產(chǎn)生ANR的上下文不同,導(dǎo)致ANR的原因也會(huì)不同;
2.ANR發(fā)生場(chǎng)景
主線程,被阻塞5秒鐘以上,就會(huì)拋出ANR對(duì)話框。不同的組件發(fā)生ANR的時(shí)間不一樣,Activity是5秒,BroadCastReceiver是10秒,Service是20秒(均為前臺(tái))。
點(diǎn)擊事件(按鍵和觸摸事件)5s內(nèi)沒(méi)被處理: Input event dispatching timed out
service 前臺(tái)20s后臺(tái)200s未完成啟動(dòng) Timeout executing service
Service Timeout是位于”ActivityManager”線程中的AMS.MainHandler收到SERVICE_TIMEOUT_MSG消息時(shí)觸發(fā)。
對(duì)于Service有兩類:
對(duì)于前臺(tái)服務(wù),則超時(shí)為SERVICE_TIMEOUT = 20s;
對(duì)于后臺(tái)服務(wù),則超時(shí)為SERVICE_BACKGROUND_TIMEOUT = 200s
BroadcastReceiver的事件(onRecieve方法)在規(guī)定時(shí)間內(nèi)沒(méi)處理完(前臺(tái)廣播為10s,后臺(tái)廣播為60s):Timeout of broadcast BroadcastRecord
以BroadcastReviever為例,在onRecieve()方法執(zhí)行10秒內(nèi)沒(méi)發(fā)生第一種ANR(也就是在這個(gè)過(guò)程中沒(méi)有輸入事件或輸入事件還沒(méi)到5s)才會(huì)發(fā)生Receiver timeout,否則將先發(fā)生事件無(wú)相應(yīng)ANR,所以onRecieve()是有可能執(zhí)行不到10s就發(fā)生ANR的,所以不要在onRecieve()方法里面干活
ContentProvider的publish在10s內(nèi)沒(méi)進(jìn)行完:timeout publishing content providers
思考一下,比如service前臺(tái)是20秒,后臺(tái)是200秒沒(méi)響應(yīng)會(huì)導(dǎo)致ANR,那么這個(gè)時(shí)間是哪里來(lái)的呢?
// How long we wait for a service to finish executing. static final int SERVICE_TIMEOUT = 20*1000; // How long we wait for a service to finish executing. static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10; mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app); void serviceTimeout(ProcessRecord proc) { String anrMessage = null; synchronized(mAm) { if (proc.executingServices.size() == 0 || proc.thread == null) { return; } final long now = SystemClock.uptimeMillis(); final long maxTime = now - (proc.execServicesFg );3.ANR發(fā)生的原理
關(guān)于ANR機(jī)制實(shí)現(xiàn)的原理可以先看這篇文章,個(gè)人覺(jué)得寫(xiě)的十分不錯(cuò),可以看看:gityuan.com/2016/07/02/…
大概原理如下:
1.在進(jìn)行相關(guān)操作調(diào)用hander.sendMessageAtTime()發(fā)送一個(gè)ANR的消息,延時(shí)時(shí)間為ANR發(fā)生的時(shí)間(如activity是當(dāng)前時(shí)間5s之后)。
2.進(jìn)行相關(guān)的操作
3.操作結(jié)束后向remove掉該條message。如果相關(guān)的操作在規(guī)定時(shí)間沒(méi)有執(zhí)行完成,該條message將被handler取出并執(zhí)行,就發(fā)生了ANR。
4.ANR有哪些具體案例
Acitvity,F(xiàn)ragment中暴力相應(yīng)點(diǎn)擊事件有可能會(huì)導(dǎo)致ANR
斷點(diǎn)調(diào)試時(shí),程序可能會(huì)出現(xiàn)ANR無(wú)限應(yīng)
主線程做了耗時(shí)操作,比如查詢數(shù)據(jù)庫(kù)數(shù)據(jù)導(dǎo)致ANR
5.ANR具體如何分析
ANR問(wèn)題是由于主線程的任務(wù)在規(guī)定時(shí)間內(nèi)沒(méi)處理完任務(wù),而造成這種情況的原因大致會(huì)有一下幾點(diǎn):
主線程在做一些耗時(shí)的工作導(dǎo)致線程卡死
主線程被其他線程鎖
cpu被其他進(jìn)程占用,該進(jìn)程沒(méi)被分配到足夠的cpu資源。
然后看anr日志。千萬(wàn)別說(shuō)不知道在哪里看日志,在發(fā)生ANR的時(shí)候,系統(tǒng)會(huì)收集ANR相關(guān)的信息提供給開(kāi)發(fā)者:首先在Log中有ANR相關(guān)的信息,其次會(huì)收集ANR時(shí)的CPU使用情況,還會(huì)收集trace信息,也就是當(dāng)時(shí)各個(gè)線程的執(zhí)行情況。trace文件保存到了/data/anr/traces.txt中
從log中找到ANR反生的信息:會(huì)包含了ANR的時(shí)間、進(jìn)程、是何種ANR等信息。
在該條log之后會(huì)有CPU usage的信息,表明了CPU在ANR前后的用量(log會(huì)表明截取ANR的時(shí)間),從各種CPU Usage信息中大概可以分析如下幾點(diǎn):
如果某些進(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)用造成的。
如果發(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)一步分析了。
如果CPU總用量不高,該進(jìn)程和其他進(jìn)程的占用過(guò)高,這有一定概率是由于某些主線程的操作就是耗時(shí)過(guò)長(zhǎng),或者是由于主進(jìn)程被鎖造成的。
除了上述分析CPU usage之后,確定問(wèn)題需要我們進(jìn)一步分析trace文件。trace文件記錄了發(fā)生ANR前后該進(jìn)程的各個(gè)線程的stack。對(duì)我們分析ANR問(wèn)題最有價(jià)值的就是其中主線程的stack,一般主線程的trace可能有如下幾種情況:
主線程是running或者native而對(duì)應(yīng)的棧對(duì)應(yīng)了我們應(yīng)用中的函數(shù),則很有可能就是執(zhí)行該函數(shù)時(shí)候發(fā)生了超時(shí)。
主線程被block:非常明顯的線程被鎖,這時(shí)候可以看是被哪個(gè)線程鎖了,可以考慮優(yōu)化代碼。如果是死鎖問(wèn)題,就更需要及時(shí)解決了。
由于抓trace的時(shí)刻很有可能耗時(shí)操作已經(jīng)執(zhí)行完了(ANR -> 耗時(shí)操作執(zhí)行完畢 ->系統(tǒng)抓trace),這時(shí)候的trace就沒(méi)有什么用了,主線程的stack就是這樣的:
總結(jié),就是兩個(gè)問(wèn)題
1.CPU 問(wèn)題
在 Monkeylog.log 文件中定位到 "anr in" 位置,查看 cpu usage ,total 占用,如發(fā)現(xiàn)接近100%,暫時(shí)判斷為 cpu 問(wèn)題。
然后在 logcat.log 文件中定位到 "not responding" 發(fā)生時(shí)間,并截取cpuinfo.log 中時(shí)間點(diǎn)前后 5s 的 log,然后計(jì)算 CPU 占中,看哪個(gè)進(jìn)程用的多,在酌情分析模塊的 CPU 占中。
2.GC 問(wèn)題
定位到 logcat.log 文件中 "not responding" 發(fā)生時(shí)間點(diǎn);
去查看發(fā)生 ANR 時(shí)間點(diǎn)對(duì)應(yīng)的 trace 文件,定位到應(yīng)用報(bào)名,若Dalvik Thread主線程顯示“SUSPENDED”,則為內(nèi)存問(wèn)題;
截取 ANR 發(fā)生時(shí)間點(diǎn)前 5s 的 log,分析 "dalvikvm" 打印的 Paused GC 耗時(shí),如果過(guò)多則定位為 GC 問(wèn)題,需要查看這 5s 件發(fā)生了哪些耗時(shí)的操作。
6.解決方案
將所有耗時(shí)操作,比如訪問(wèn)網(wǎng)絡(luò),Socket通信,查詢大量SQL 語(yǔ)句,復(fù)雜邏輯計(jì)算等都放在子線程中去,然 后通過(guò)handler.sendMessage、runonUIThread、AsyncTask 等方式更新UI。無(wú)論如何都要確保用戶界面作的流暢 度。如果耗時(shí)操作需要讓用戶等待,那么可以在界面上顯示度條。
使用AsyncTask處理耗時(shí)IO操作。在一些同步的操作主線程有可能被鎖,需要等待其他線程釋放相應(yīng)鎖才能繼續(xù)執(zhí)行,這樣會(huì)有一定的ANR風(fēng)險(xiǎn),對(duì)于這種情況有時(shí)也可以用異步線程來(lái)執(zhí)行相應(yīng)的邏輯。另外, 要避免死鎖的發(fā)生。
使用Thread或者HandlerThread時(shí),調(diào)用Process.setThreadPriority(Process.THREADPRIORITYBACKGROUND)設(shè)置優(yōu)先級(jí),否則仍然會(huì)降低程序響應(yīng),因?yàn)槟J(rèn)Thread的優(yōu)先級(jí)和主線程相同。
使用Handler處理工作線程結(jié)果,而不是使用Thread.wait()或者Thread.sleep()來(lái)阻塞主線程。
Activity的onCreate和onResume回調(diào)中盡量避免耗時(shí)的代碼
BroadcastReceiver中onReceive代碼也要盡量減少耗時(shí),建議使用IntentService處理。
各個(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
7.ANR問(wèn)題解答
ANR有異常日志嗎?或者說(shuō)ANR在第三方崩潰日志中有日志嗎?
沒(méi)有異常日志,因?yàn)楸旧聿粚儆贓rror或者Exception
關(guān)于其他內(nèi)容介紹
01.關(guān)于博客匯總鏈接
1.技術(shù)博客匯總
2.開(kāi)源項(xiàng)目匯總
3.生活博客匯總
4.喜馬拉雅音頻匯總
5.其他匯總
02.關(guān)于我的博客
我的個(gè)人站點(diǎn):www.yczbj.org,www.ycbjie.cn
github:github.com/yangchong21…
知乎:www.zhihu.com/people/yang…
簡(jiǎn)書(shū):www.jianshu.com/u/b7b2c6ed9…
csdn:my.csdn.net/m0_37700275
喜馬拉雅聽(tīng)書(shū):www.ximalaya.com/zhubo/71989…
開(kāi)源中國(guó):my.oschina.net/zbj1618/blo…
泡在網(wǎng)上的日子:www.jcodecraeer.com/member/cont…
郵箱:yangchong211@163.com
阿里云博客:yq.aliyun.com/users/artic… 239.headeruserinfo.3.dT4bcV
segmentfault頭條:segmentfault.com/u/xiangjian…
項(xiàng)目地址:github.com/yangchong211
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/7035.html
摘要:內(nèi)存泄漏當(dāng)應(yīng)用內(nèi)部不再需要某個(gè)實(shí)例后,但是這個(gè)對(duì)象卻仍然被引用,這個(gè)情況就叫做內(nèi)存泄露。安卓虛擬機(jī)為每一個(gè)應(yīng)用分配一定的內(nèi)存空間,當(dāng)內(nèi)存泄露到達(dá)一定的程度就會(huì)造成內(nèi)存溢出。點(diǎn)擊登錄跳轉(zhuǎn)頁(yè)面中所有操作都與用戶密切相關(guān),是 Android: 今日頭條屏幕適配的原理? 1:首先計(jì)算出 density,計(jì)算公式:當(dāng)前設(shè)備屏幕總寬度(單位為像素)/ 設(shè)計(jì)圖總寬度(單位為 dp) = densit...
閱讀 713·2023-04-25 19:43
閱讀 3910·2021-11-30 14:52
閱讀 3784·2021-11-30 14:52
閱讀 3852·2021-11-29 11:00
閱讀 3783·2021-11-29 11:00
閱讀 3869·2021-11-29 11:00
閱讀 3558·2021-11-29 11:00
閱讀 6105·2021-11-29 11:00