后臺Crash
蘋果在 WWDC 2020 上的介紹,目前會導(dǎo)致App在后臺被殺死的情況大概有以下 6 種辟癌。
1寒屯、崩潰(Crashes)
代碼邏輯的Crash引發(fā)App閃退。
2黍少、CPU資源限制(CPU resource limit)
后臺長時間占用CPU資源過高(High sustained CPU load in background)
3寡夹、看門狗(Watchdog)
Exception Type: EXC_CRASH (SIGKILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: Namespace SPRINGBOARD, Code 0x8badf00d
- 死鎖
- 無限循環(huán)
- 同步操作
注意APP在不同的生命周期,看門狗的超時時間是不同的厂置,前臺正常運(yùn)行時菩掏,超時時間為20s。
4昵济、內(nèi)存超出系統(tǒng)限制(Memory limit exceeded)
APP占用內(nèi)存超過閾值(App using too much memory)
閾值在前臺和后臺是一樣的智绸,但是不同設(shè)備不一樣(Same limit for foreground and background)
越老的設(shè)備閾值越低或颊,6S以前設(shè)備使用內(nèi)存不要超過200MB(Keep in mind older devices(such as before 6S,Limit is 200MB))
5、內(nèi)存自動清理(Memory pressure exit)
通常不是程序問題(Not a bug with you app)传于,無法避免
系統(tǒng)為了給其他APP內(nèi)存而殺掉后臺的程序機(jī)制
盡量保證程序在后臺占用內(nèi)存小于50MB(Aim for less than 50MB in the background)
6、后臺任務(wù)超時(Background task timeout)
執(zhí)行后臺任務(wù)時醉顽,未在30s內(nèi)結(jié)束后臺任務(wù)(Failure ro end the task explicitly result in termination.(in 30s))
可以使用以下方法
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void(^ __nullable)(void))handler API_AVAILABLE(ios(4.0)) NS_REQUIRES_SUPER;
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithName:(nullable NSString *)taskName expirationHandler:(void(^ __nullable)(void))handler API_AVAILABLE(ios(7.0)) NS_REQUIRES_SUPER;
- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier API_AVAILABLE(ios(4.0)) NS_REQUIRES_SUPER;
這個方法為你的應(yīng)用程序請求額外的后臺執(zhí)行時間沼溜。當(dāng)在App即將進(jìn)入后臺,而這時候有些task還沒來得及完成游添,這時候可以使用這個方法系草,將額外為App增加30秒的運(yùn)行時間,這方法是和endBackgroundTask
方法配對使用唆涝,一般在- (void)applicationDidEnterBackground:(UIApplication *)application
方法內(nèi)使用找都。如果超過30秒,后臺任務(wù)還沒結(jié)束廊酣,App將會被系統(tǒng)強(qiáng)制殺死能耻,而不是進(jìn)入Suspended
狀態(tài)。
- (void)applicationDidEnterBackground:(UIApplication *)application
{
__block UIBackgroundTaskIdentifier taskID = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:taskID];
taskID = UIBackgroundTaskInvalid;
}];
}
冷啟動和熱啟動
- 冷啟動:指APP被后臺kill后重新啟動APP亡驰,這種啟動方式叫做冷啟動晓猛。
- 熱啟動:APP的狀態(tài)由running切換為suspend,APP 沒有被kill仍然在后臺運(yùn)行凡辱。再次把APP切換到前臺戒职,這種啟動方式叫熱啟動。
Suspended狀態(tài)
程序在后臺不能執(zhí)行代碼透乾。系統(tǒng)會自動把程序變成這個狀態(tài)而且不會發(fā)出通知洪燥。當(dāng)掛起時,程序還是停留在內(nèi)存中的乳乌,當(dāng)系統(tǒng)內(nèi)存低時捧韵,系統(tǒng)就把掛起的程序清除掉,為前臺程序提供更多的內(nèi)存钦扭。
OOM
以下纫版,重點(diǎn)說一下第5、內(nèi)存自動清理(Memory pressure exit)
在iOS中客情,當(dāng)前應(yīng)用因?yàn)閮?nèi)存占用過高而被操作系統(tǒng)強(qiáng)制終止其弊,從設(shè)備設(shè)置-隱私-分析與改進(jìn)中是找不到普通類型的崩潰日志,只能夠找到Jetsam開頭的日志膀斋,這種形式的日志其實(shí)就是 OOM 崩潰之后系統(tǒng)生成的一種專門反映內(nèi)存異常問題的日志梭伐。
OOM 分為
FOOM(Foreground Out Of Memory)
BOOM(background Out Of Memory)
Jetsam是 iOS 操作系統(tǒng)為了控制內(nèi)存資源過度使用而采用的一種資源管控機(jī)制。不同于MacOS仰担,Linux糊识,Windows等桌面操作系統(tǒng),出于性能方面的考慮,iOS 系統(tǒng)并沒有設(shè)計內(nèi)存交換空間的機(jī)制赂苗,所以在 iOS 中愉耙,如果設(shè)備整體內(nèi)存緊張的話,系統(tǒng)只能將一些優(yōu)先級不高或占用內(nèi)存過大的進(jìn)程直接終止掉拌滋。Jetsam機(jī)制終止進(jìn)程的時候最終是通過發(fā)送SIGKILL
異常信號來完成的朴沿,但是SIGKILL
信號不可以在當(dāng)前進(jìn)程被忽略或者被捕獲。所以可以使用排除法來得到是否發(fā)生了FOOM败砂,排除已知的能收到Crash signal的類型赌渣,剩下的就是不能收到signal的SIGKILL
類型Crash,這種方法不是很精準(zhǔn)昌犹。
SIGKILL
此信號表示系統(tǒng)中止進(jìn)程坚芜,通常是調(diào)用函數(shù)exit()
或kill(9)
產(chǎn)生。
常見的Crash編碼類型如下斜姥,上述所說的OOM也是發(fā)送SIGKILL
來終止App的鸿竖。
常見SIGKILL
類型
0x8badf00d:ate bad food,觸發(fā)系統(tǒng)看門狗铸敏。
0xc00010ff:cool off千贯,系統(tǒng)由于過熱保護(hù)中止應(yīng)用。
0xbada5e47:Background Task任務(wù)超時(30s)
SIGKILL
等價于kill -9
搞坝,它是用來殺死僵尸進(jìn)程搔谴;而SIGABRT
等價于kill -6
,它是用來殺死正在運(yùn)行的進(jìn)程桩撮。
SIGKILL
不能被捕獲或忽略敦第,也就是說此類 Crash 第三方的收集框架捕獲不到,此時在只可以在用戶的設(shè)備中能找到操作系統(tǒng)生成的卡死崩潰日志店量。而SIGABRT
可以被捕獲芜果,但不能阻塞。
MetricKit
注意:iOS 13推出的MetricKit框架融师,其中應(yīng)用程序退出
是 MetricKit 在 iOS 14 上新增的一個指標(biāo) MXAppExitMetric 右钾。他統(tǒng)計的是每天應(yīng)用程序在前臺、后臺運(yùn)行的時候退出或被殺的原因概述旱爆。
使用MXBackgrounndExitData(iOS14 MetricKit)能夠統(tǒng)計的數(shù)據(jù)
* cumulativeNormalAppExitCount:正常退出次數(shù)
* cumulativeMemoryResourceLimitExitCount:內(nèi)存OOM引起程序退出次數(shù)
* cumulativeCPUResourceLimitExitCount:cpu資源超限引起退出次數(shù)
* cumulativeMemoryPressureExitCount:系統(tǒng)內(nèi)存自動清理引起退出次數(shù)
* cumulativeBadAccessExitCount:非法訪問(SIGSEGV/SIGBUS)引起退出次數(shù)
* cumulativeAbnormalExitCount:Abort函數(shù)中止引起退出次數(shù)
* cumulativeIllegalInstructionExitCount:非法指令(SIG)引起退出次數(shù)
* cumulativeAppWatchdogExitCount:看門狗(WatchDog)引起的退出次數(shù)
* cumulativeSuspendedWithLockedFileExitCount:后臺讀寫文件引起的退出次數(shù)
* cumulativeBackgroundTaskAssertionTimeoutExitCount:后臺任務(wù)超時引起的退出次數(shù)
參考
https://developer.apple.com/videos/play/wwdc2020/10078/
https://www.infoq.cn/article/ox7u3ymwiwzamt1vgm7m