前言
為了防止一個應用占用過多的系統(tǒng)資源,蘋果設(shè)計了一個“看門狗”( watchdog )的機制。在不同的場景下,“看門狗”會監(jiān)測應用的性能。如果超出了該場景所規(guī)定的運行時間,“看門狗”就會強制終結(jié)這個應用的進程。開發(fā)者們在 crashlog 里面,會看到諸如 0x8badf00d 這樣的錯誤代碼。異常代碼:“ 0x8badf00d ”,即“ ate bad food ”。
The exception code
0x8badf00dindicates that an application has been terminated by iOS because a watchdog timeout occurred. The application took too long to launch, terminate, or respond to system events. One common cause of this is doing synchronous networking on the main thread.
Whatever operation is onThread 0needs to be moved to a background thread, or processed differently, so that it does not block the main thread.
大致意思是說:如果我們的應用程序?qū)σ恍┨囟ǖ腢I事件(比如啟動、掛起、恢復、結(jié)束)響應不及時,Watchdog 會把我們的應用程序干掉,并生成一份響應的 crash 報告。
遇到的問題
應用 100% Loss 時完全無法啟動,一直崩潰。徹底切斷網(wǎng)絡連接正常啟動,調(diào)試模式狀態(tài)下等待時間非常久,但可以啟動,并伴隨 UI 微卡。強烈的預感這是線程阻塞。
注:用 Xcode debug 時 watchdog 并不運行,一定要把設(shè)備從 Xcode 斷開來測試啟動速度。
原因
首先看了 crash log,就像猜測的那樣,的確是卡在了主線程;意料之外的是,無數(shù)次閃退只留下了一份崩潰日志,如下所示:

第一次見,讀了一些資料大概才算是明白了這是怎么一回事。為了避免應用陷入錯誤狀態(tài)導致界面無響應,
Apple 設(shè)計了看門狗 (WatchDog) 機制。一旦超時,強制殺死進程。在不同的生命周期,觸發(fā)看門狗機制的超時時間有所不同:
首先說一說異常編碼,也是寓意頗深。8badf00d = ate bad food,大概是在說看門狗吃了壞的食物所以暴走了?!異常記錄則表示這并不是一次崩潰(邪魅一笑:強制退出而已)。信息一欄指出時間限制為 20 s。結(jié)合應用業(yè)務來看,表層原因在于:每次啟動應用,首先進行一次模版同步,在此之前需要檢測登錄狀況,通過 RunLoop 反復嘗試直到收到響應為止。然而不幸的是,這一些都發(fā)生在主線程。
同步網(wǎng)絡請求,主線程,超長超時時間,滿足這三點,一定場景下幾乎必然會觸發(fā)看門狗機制。
對策
合理解決方案:
異步網(wǎng)絡請求:優(yōu)點很多,最重要的是可以讓你無憂無慮安全地訪問網(wǎng)絡,而無需擔心線程。
在非主線程中使用同步網(wǎng)絡請求:如果異步運行你的網(wǎng)絡代碼比登天還難的話(也許你的應用是一個基于同步網(wǎng)絡請求的大型移植項目),退而求次,你也可以在次級線程中運行同步代碼,也可以避免觸發(fā)看門狗機制。
此外,一部分情況下,例如這次遇到登錄和模版同步時觸發(fā)看門狗,事實上,即使在運用到模版時再次請求也是勉強可行的,因此姑且先跳過網(wǎng)絡請求也可以。此時,還以使用一種我認為是相對比較差的方案:
- 通過
RunLoop來操控一切,一旦超過既定的超時時間,就提示用戶重試或者暫時先跳過網(wǎng)絡請求。
應用的網(wǎng)絡部分基于公司的通用框架,因此優(yōu)先考慮在非主線程中進行網(wǎng)絡請求來避免觸發(fā)看門狗。
至于調(diào)試模式下為什么可以正常啟動應用,完全是因為該模式下看門狗機制處于禁用狀態(tài)。
此外,除了網(wǎng)絡操作,I/O 讀寫文件和大規(guī)模運算等耗時任務也極有可能觸發(fā)看門狗機制。合理處理線程,優(yōu)化耗時任務,很大程度能避免不佳用戶體驗。
Author
如果你有什么建議,可以關(guān)注我,直接留言,留言必回。
參考文章
主線程上的同步網(wǎng)絡請求
調(diào)試模式不發(fā)生崩潰
iOS的看門狗(watchdog)機制
iOS的看門狗機制