iOS后台Crash可能情况
后台Crash
苹果在 WWDC 2020 上的介绍,目前会导致App在后台被杀死的情况大概有以下 6 种。
1、崩溃(Crashes)
代码逻辑的Crash引发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
- 死锁
- 无限循环
- 同步操作 注意APP在不同的生命周期,看门狗的超时时间是不同的,前台正常运行时,超时时间为20s。
4、内存超出系统限制(Memory limit exceeded)
APP占用内存超过阈值(App using too much memory) 阈值在前台和后台是一样的,但是不同设备不一样(Same limit for foreground and background) 越老的设备阈值越低,6S以前设备使用内存不要超过200MB(Keep in mind older devices(such as before 6S,Limit is 200MB))
5、内存自动清理(Memory pressure exit)
通常不是程序问题(Not a bug with you app),无法避免 系统为了给其他APP内存而杀掉后台的程序机制 尽量保证程序在后台占用内存小于50MB(Aim for less than 50MB in the background)
6、后台任务超时(Background task timeout)
执行后台任务时,未在30s内结束后台任务(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;
这个方法为你的应用程序请求额外的后台执行时间。当在App即将进入后台,而这时候有些task还没来得及完成,这时候可以使用这个方法,将额外为App增加30秒的运行时间,这方法是和endBackgroundTask
方法配对使用,一般在- (void)applicationDidEnterBackground:(UIApplication *)application
方法内使用。如果超过30秒,后台任务还没结束,App将会被系统强制杀死,而不是进入Suspended
状态。
- (void)applicationDidEnterBackground:(UIApplication *)application
{
__block UIBackgroundTaskIdentifier taskID = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:taskID];
taskID = UIBackgroundTaskInvalid;
}];
}
冷启动和热启动
- 冷启动:指APP被后台kill后重新启动APP,这种启动方式叫做冷启动。
- 热启动:APP的状态由running切换为suspend,APP 没有被kill仍然在后台运行。再次把APP切换到前台,这种启动方式叫热启动。
Suspended状态 程序在后台不能执行代码。系统会自动把程序变成这个状态而且不会发出通知。当挂起时,程序还是停留在内存中的,当系统内存低时,系统就把挂起的程序清除掉,为前台程序提供更多的内存。
OOM
以下,重点说一下第5、内存自动清理(Memory pressure exit)
在iOS中,当前应用因为内存占用过高而被操作系统强制终止,从设备设置-隐私-分析与改进中是找不到普通类型的崩溃日志,只能够找到Jetsam开头的日志,这种形式的日志其实就是 OOM 崩溃之后系统生成的一种专门反映内存异常问题的日志。
OOM 分为 FOOM(Foreground Out Of Memory) BOOM(background Out Of Memory)
Jetsam是 iOS 操作系统为了控制内存资源过度使用而采用的一种资源管控机制。不同于MacOS,Linux,Windows等桌面操作系统,出于性能方面的考虑,iOS 系统并没有设计内存交换空间的机制,所以在 iOS 中,如果设备整体内存紧张的话,系统只能将一些优先级不高或占用内存过大的进程直接终止掉。Jetsam机制终止进程的时候最终是通过发送SIGKILL
异常信号来完成的,但是SIGKILL
信号不可以在当前进程被忽略或者被捕获。所以可以使用排除法来得到是否发生了FOOM,排除已知的能收到Crash signal的类型,剩下的就是不能收到signal的SIGKILL
类型Crash,这种方法不是很精准。
SIGKILL
此信号表示系统中止进程,通常是调用函数exit()
或kill(9)
产生。 常见的Crash编码类型如下,上述所说的OOM也是发送SIGKILL
来终止App的。 常见SIGKILL
类型
0x8badf00d:ate bad food,触发系统看门狗。
0xc00010ff:cool off,系统由于过热保护中止应用。
0xbada5e47:Background Task任务超时(30s)
SIGKILL
等价于kill -9
,它是用来杀死僵尸进程;而SIGABRT
等价于kill -6
,它是用来杀死正在运行的进程。
SIGKILL
不能被捕获或忽略,也就是说此类 Crash 第三方的收集框架捕获不到,此时在只可以在用户的设备中能找到操作系统生成的卡死崩溃日志。而SIGABRT
可以被捕获,但不能阻塞。
MetricKit
注意:iOS 13推出的MetricKit框架,其中应用程序退出
是 MetricKit 在 iOS 14 上新增的一个指标 MXAppExitMetric 。他统计的是每天应用程序在前台、后台运行的时候退出或被杀的原因概述。
image.jpeg
使用MXBackgrounndExitData(iOS14 MetricKit)能够统计的数据
* cumulativeNormalAppExitCount:正常退出次数
* cumulativeMemoryResourceLimitExitCount:内存OOM引起程序退出次数
* cumulativeCPUResourceLimitExitCount:cpu资源超限引起退出次数
* cumulativeMemoryPressureExitCount:系统内存自动清理引起退出次数
* cumulativeBadAccessExitCount:非法访问(SIGSEGV/SIGBUS)引起退出次数
* cumulativeAbnormalExitCount:Abort函数中止引起退出次数
* cumulativeIllegalInstructionExitCount:非法指令(SIG)引起退出次数
* cumulativeAppWatchdogExitCount:看门狗(WatchDog)引起的退出次数
* cumulativeSuspendedWithLockedFileExitCount:后台读写文件引起的退出次数
* cumulativeBackgroundTaskAssertionTimeoutExitCount:后台任务超时引起的退出次数
发表回复