iOS内功篇:浅谈Crash
2017-12-01 10:37
编辑: suiling
分类:iOS开发
iOS开发中,解决Crash相信是开发者最为头疼的问题了,特别是对于已上线的应用,对其Crash的跟踪和修复显得尤其重要,本文主要总结了常见的Crash类型以及主流的Crash日志收集及解析的解决方案。
本文主要目录:
Crash分为两种,未捕获的Objective-C异常和Mach异常。
一、Objective-C Exception
在OC层面(iOS库、第三方库出现错误抛出)的异常称为OC异常。
比如:
OC异常可以用try-catch抓住:
使用此方法可以抓到当前抛出的异常并阻止程序崩溃,然而苹果爸爸并不推荐这样去做。
常见的OC异常
OC异常的抓取和分析
在debug环境下,OC异常导致崩溃时Xcode控制台会输出完整的异常信息,比如:
Terminating app due to uncaught exception ‘NSRangeException’, reason: ‘this is reason description’,包括Exception的类型、原因和发生异常的完整堆栈。
这些信息一般来说都足够详细,足够我们轻易地找到异常的位置并进行修复。
非debug环境下,可以通过注册 NSUncaughtExceptionHandler 捕获异常信息。虽然无法阻止APP崩溃,但是可以获取异常信息并进行收集,下次启动APP时进行上报,方便开发者进行错误跟踪及修复,这就是常用Crash收集工具所做的事情。
Mach Exception
Mach异常是指最底层的内核级异常。
最常见的Mach异常:EXC_BAD_ACCESS (Bad Memory Access)
这种内存访问异常分为访问非法地址(SIGBUS信号)和访问了被回收掉的内存(SIGSEGV信号),实际开发中遇到的错误通常令人莫名其妙,往往需要大量时间来排查,非常头疼。
EXC_BAD_ACCESS后面通常带有code来帮助我们判断到底是什么错误,比如EXC_I386_GPFLT指访问了一块已经不属于你的内存。
一些其他的Mach异常:
- EXC_BAD_INSTRUCTION运行了非法的指令,往往是运行指令的参数不对(0或者nil的参数)
- EXC_RESOURCE程序资源上限(cpu占用过高或者内存不足)。
- EXC_GUARD一些C函数访问错误导致的异常。
- 0x00000020奇怪异常集合,常见的是由于主线程阻塞看门狗杀死了APP《Exception Type: 00000020:什么是看门狗机制》
Unix Signal Exception
从Mach异常最终会转化成Unix信号投递到出错的线程(具体原理可以学习《漫谈iOS Crash收集框架》, 各种信号的含义可以学习《iOS异常捕获》。
- OC异常并不是真正的异常,但是当一个OC异常被抛出到最外层还没被捕获,程序会强行发送SIGABRT信号中断程序。
- Mach异常没有比较便利的捕获方式,既然它最终会转化成信号,我们也可以通过捕获信号,来捕获 Crash 事件。
iOS提供了signal方法来注册一个处理函数,在处理函数中,使用execinfo中的 backtrace_symbols取出汇编层程序的堆栈信息。
代码如下: