最近在解决crash。说一下我对三个概念的理解。说的不对的也希望能被指出。
OSX、 iOS系统架构
介绍
Mach异常是指最底层的内核异常。用户态的开发者可以直接使用Mach Api设置Thread,task,host等异常端口,捕获mach异常。 Unix信号又称BSD信号。如果开发者没有捕获到Mach异常。则会被host层的方法 ux_exception()将异常转换为对应的Unix信号。并通过方法threadsignal()将信号投递到出错线程。 可以通过方法signal(x,SignalHandler)捕获single. NSException 应用级错误。可以通过try catch捕获。或者通过NSSetUncaughtExceptionHandler()函数处理一下crash前的事情。
异常关系
因为硬件产生的信号(cpu陷阱)被Mach层捕获。转换为对应的Unix信号。 但是苹果为了统一机制。操作系统和用户产生的异常(kill和pthread_kill)也首先沉下来被转换为Mach异常。然后转换为对应的Unix信号
EXC_BAD_ACCESS是Mach异常。
EXC_BAD_ACCESS is a Mach exception sent by the kernel to your application when you try to access memory that is not mapped for your application. If not handled at the Mach level, it will be translated into a SIGBUS or SIGSEGV BSD signal.
SIGABRT is a BSD signal sent by an application to itself when an NSException or obj_exception_throw is not caught.
也就是说未被try catch的NSException会发出kill或pthread_kill信号-> Mach异常-> Unix信号(SIGABRT)。
SIGABRT is a BSD signal sent by an application to itself when an NSException or obj_exception_throw is not caught.
如何判断crash原因是Mach异常还是NSException 若程序因NSExcetption而crash 系统中的Last Exception backtrace信息是完整准确的 NSException如果没有被try catch 它转化为的Unix信号是SIGABRT
常用的Unix信号
- SIGSEGV 试图访问未分配给自己的内存 或试图往没有没有写权限的内存地址写数据,比如给release对象发送消息
- SIGBUS:非法地址 包括内存地址对齐
- SIGABRT是调用abort()生成的信号。很有可能是NSException 也有可能是Mach异常
异常捕获问题
为什么第三方库PLCrashReport即使在优选捕获Mach异常的情况下,也放弃捕获捕获Mach异常EXC_Crash 而选择阈值对应的SIGABRT信号?
We still need to use signal handlers to catch SIGABRT in-process. The kernel sends an EXC_CRASH mach exception to denote SIGABRT termination. In that case, catching the Mach exception in-process leads to process deadlock in an uninterruptable wait. Thus, we fall back on BSD signal handlers for SIGABRT, and do not register for EXC_CRASH.
既然未被try catch的NSException最终会转为Unix信号,为什么还需要 Set the uncaught exception handler
NSException会有更多的信息,获取它的reason,name,callStackSymbols信息才能确定出问题的程序位置。
参考 wangdetong.github.io/2016/07/20/… www.jianshu.com/p/725e7d692…