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