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 。他统计的是每天应用程序在前台、后台运行的时候退出或被杀的原因概述。

img

image.jpeg

使用MXBackgrounndExitData(iOS14 MetricKit)能够统计的数据

*   cumulativeNormalAppExitCount:正常退出次数
*   cumulativeMemoryResourceLimitExitCount:内存OOM引起程序退出次数
*   cumulativeCPUResourceLimitExitCount:cpu资源超限引起退出次数
*   cumulativeMemoryPressureExitCount:系统内存自动清理引起退出次数
*   cumulativeBadAccessExitCount:非法访问(SIGSEGV/SIGBUS)引起退出次数
*   cumulativeAbnormalExitCount:Abort函数中止引起退出次数
*   cumulativeIllegalInstructionExitCount:非法指令(SIG)引起退出次数
*   cumulativeAppWatchdogExitCount:看门狗(WatchDog)引起的退出次数
*   cumulativeSuspendedWithLockedFileExitCount:后台读写文件引起的退出次数
*   cumulativeBackgroundTaskAssertionTimeoutExitCount:后台任务超时引起的退出次数

评论

0条评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注