iOS crash 收集与分析

一、收集方式

1、设备收集

a.使用Xcode从设备获取崩溃日志

把你的手机连接到Mac,并选择Xcode->Windows->Device and Simulator,然后点击View Device Logs,你会看到手机上会有好多Log,其中Type为Crash的就是崩溃的Log,如下图:

crash1.webp

b.通过设备直接获取崩溃日志

1)打开设置->隐私->分析->分析数据,在其中找到你想要的应用程序的日志,日志将使用以下格式命名:<应用名称> _ <崩溃时间> _ <设备名>
2)选择所需的日志,复制文本或点击右上角的分享按钮分享出去,并且把分享得到的.ips.synced或者复制文本而来的.txt文件的后缀名改为.crash,因为Xcode不接受没有.crash扩展名的崩溃日志。

2、苹果爸爸发送 crash 报告

16进制数字

dSYM

符号集是我们每次Archive一个包之后,都会随之生成的.dSYM文件,这个文件必须使用Xcode进行打包才有(Debug模式默认是关闭的)。每次发布一个版本,我们都需要备份这个文件,以方便以后的调试。
符号集中存储着文件名、函数名、行号与内存地址的映射表,通过符号集分析崩溃的.Crash文件可以准确知道具体的崩溃信息。
我们如果不使用.dSYM文件获取到的崩溃信息都是不完全的(官方文档说了会导致不完全符号化,也就是一部分符号化好了,一部分没有)。
每一个.dSYM文件都有一个UUID,和.app文件中的UUID对应,代表着是一个应用,而.dSYM文件中每一条崩溃信息也有一个单独的UUID,用来和程序的UUID进行校对。
复制代码

二、校验

在符号化Crash文件之前,你需要准备好.crash和.dSYM并校验是否匹配

为什么要校验:

因为符号集存储着文件名、函数名、行号的信息,每一次代码更改后编译符号集也会随之变更,所以要想符号化.crash文件,.crash与符号集必须一一对应
也就是说由版本为1.0的代码生成了1.0的APP,同时生成了1.0的符号集,1.0的APP发生了Bug,生成了104115的crash文件,也只有1.0的符号集才能够符号化104115的crash文件,而同时也必须找到1.0的代码才能根据符号化的crash文件精确定位到bug产生的地方。
如何判断.crash、.dSYM与.app(是否匹配你的代码)是否匹配?
通过UUID来匹配,UUID是Xcode在编译时自动为每个版本生成的唯一标识,即使功能相同的可执行文件是使用相同的编译器设置从相同的源代码重建的,它也将具有不同的构建UUID,总之UUID是唯一的。
如何通过命令行获取UUID?
获取.crash的UUID

grep "'Your AppName' arm64" t.crash
复制代码

获取.dSYM的UUID

dwarfdump --uuid 'Your AppName'.app.dSYM
复制代码

获取.app的的UUID

dwarfdump --uuid 'Your AppName'.app/'Your AppName'
复制代码

三、符号化文件

通过dSYM中存储的信息可以把crash日志中的16进制数字一一对应成我们看得懂的文件名、函数名和行号,这个过程就叫做**符号化**
复制代码

1、通过XCode自动符号化Crash文件

2、通过命令行工具symbolicatecrash符号化

四、分析

crash 类型

1、EXC_BAD_ACCESS

坏内存访问

野指针引起的崩溃,访问了一个已经释放的内存而导致,向已经释放的对象或向它发送消息时,EXC_BAD_ACCESS就会出现。造成EXC_BAD_ACCESS最常见的原因是,在初始化方法中初始化变量时用错了所有权修饰符,这会导致对象过早地被释放。
复制代码

引起坏内存的 signal 类型

  • SIGSEGV

      对象已经被释放,内存不合法,此块内存地址又没被覆盖,所以此内存内垃圾内存,所以调用方法的时候会导致SIGSEGV的错误
    复制代码
  • SIGBUS

     内存地址未对齐
    复制代码
  • SIGABRT

      导致SIGABRT的错误,因为内存中根本就没有这个空间
    复制代码

僵尸对象解决

是一个环境变量,用来调试与内存相关的问题,跟踪对象的释放过程。启用了NSZombieEnabled的话,它会用一个僵尸实现来去你的默认的dealloc实现,也就是在引用计数降到0时,该僵尸实现会将该对象转换成僵尸对象。僵尸对象的作用是在你向它发送消息时,它会显示一段日志并自动跳入调试器
复制代码

2、EXC_ARITHETIC

除 0 操作

3、SIGILL

SIGILL代表signal illegal instruction(非法指令信号)。当在处理器上执行非法指令时,它就会发生。执行非法指令是指,将函数指针会给另外一个函数时,该函数指针由于某种原因是坏的,指向了一段已经释放的内存或是一个数据段。有时你收到的是EXC_BAD_INSTRUCTION而不是SIGILL,虽然它们是一回事,不过EXC_*等同于此信号不依赖体系结构。
复制代码

4、SIGABRT

SIGABRT代表SIGNAL ABORT(中止信号)。当操作系统发现不安全的情况时,它能够对这种情况进行更多的控制;必要的话,它能要求进程进行清理工作。在调试造成此信号的底层错误时,并没有什么妙招

一般表示内存根本没这个空间
复制代码

5、SIGBUS

  内存未对齐
复制代码

5、watchdog 超时

在iOS上,它经常出现在执行一个同步网络调用而阻塞主线程的情况。因此,永远不要进行同步网络调用。
复制代码

五、Mach异常和Signal信号

blog.csdn.net/u013602835/…

如果想要监听异常其实就是去监听Mach异常和Signal信号。其实系统已经给我们提供了一个方法去监听程序产生的异常,通过NSSetUncaughtExceptionHandler(入参是一个C函数)方法就可以直接捕获异常信息。但是这个方法捕获的异常有限,不能捕获由于内存访问错误等产生的signal,所以如果想要监听绝大多数的异常需要我们自己通过注册signal(signal的类型,回调方法)来捕获信号进行监听。

void InstallUncaughtExceptionHandler(void) {
    NSSetUncaughtExceptionHandler(&HandleException); //系统的方法
    //添加想要监听的signal类型,当发出相应类型的signal时,会回调SignalHandler方法
    signal(SIGABRT, SignalHandler);
    signal(SIGILL, SignalHandler);
    signal(SIGSEGV, SignalHandler);
    signal(SIGFPE, SignalHandler);
    signal(SIGBUS, SignalHandler);
    signal(SIGPIPE, SignalHandler);
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享