iOS崩溃捕获以及收集原理

4,185 阅读3分钟

通过崩溃捕获和收集,可以收集到已发布应用(游戏)的异常,以便开发人员发现和修改bug,对于提高软件质量有着极大的帮助,本文主要介绍iOS平台下崩溃捕获和收集的原理及步骤。

要实现崩溃捕获和收集的步骤如下:

      1、捕获崩溃

      2、获取堆栈信息

      3、符号表还原

      4、服务器上传

捕获异常

iOS中引发崩溃的代码本质上就两类,信号可捕捉的崩溃和 信号不可捕捉崩溃。

信号可捕捉的崩溃

  1. unrecognized selector crash (没找到对应的函数)
  2. KVO crash :(KVO的被观察者dealloc时仍然注册着KVO导致的crash,添加KVO重复添加观察者或重复移除观察者 )
  3. NSNotification crash:(当一个对象添加了notification之后,如果dealloc的时候,仍然持有notification)
  4. NSTimer类型crash:(需要在合适的时机invalidate 定时器,否则就会由于定时器timer强引用target的关系导致 target不能被释放,造成内存泄露,甚至在定时任务触发时导致crash)
  5. Container类型crash:(数组,字典,常见的越界,插入,nil)
  6. 野指针类型的crash
  7. 非主线程刷UI类型:(在非主线程刷UI将会导致app运行crash)

NSException的异常比较简单,直接获取崩溃name,reason和callstack;signal的堆栈的处理就比较麻烦些;另外,还就是需要分析APP的当前线程信息以及所有的线程信息或者更加深一步的寄存器信息。不过这个时候拿到的堆栈是地址的形式,还需要第三步的符号表还原功能才能定位到代码行号。

iOS中引发崩溃的代码本质上就两类,一个是c++语言层面的错误,属于比较底层的错误,比如野指针,除零,内存访问异常等等,这一类的错误可以通过信号机制来捕获(signal或者是sigaction),即任何系统错误都会抛出一个错误信号,我们可以通过设定一个回调函数,然后在回调函数里面进行自己的处理;另一类是未捕获异常(Uncaught Exception),iOS下面最常见的就是objective-c的NSException,比如,数组访问元素越界。这些异常如果没有在最上层try住,那么程序就崩溃了。

针对NSException的捕获,通过调用NSSetUncaughtExceptionHandler来捕获,系统错误通过注册signal来捕获,一般产生一个NSException的异常的时候,同时也会抛出一个signal的信号。

如果要做得全面,除了处理Object-C项目,还需要处理Swift语言编写的项目,另外还有就是U3D的工程,移动游戏开发很多都是使用这个。

注意:在分析堆栈信息时需要区分32位和64位,以及分别处理真机和模拟器的堆栈,因为一个是arm架构,一个是x86_ 64。

信号不可捕捉的崩溃

  1. 后台任务超时
  2. App超过系统限制的内存大小被杀死
  3. 主线程卡顿被杀死

符号表还原

符号表还原包括系统符号表和App自己的符号表这两类。

系统符号表的话,比较坑爹,需要有不同系统版本的手机,分别拿到他们的系统符号表,解析出来,没有找到一个Apple提供的统一系统symbol文件下载地址;App的符号表,Build的时候都会生成。通过分析dwarf文件架构,解析出对应的符号表,然后和第二步的结果比照还原