iOS crash 收集与分析

objc_818
texture 异步渲染和布局引擎 应用启动 dyld 动态库 调用 libobjc动态库 --> _objc_init方法 (map_images(镜像文件) + load_images(load 方法)) - mainweb

  • load 启动 - lazy_class(不调用 load 方法 就是 lazy_class)

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扩展名的崩溃日志。markdown

二、苹果爸爸发送 crash 报告

16进制数字网络

dSYM

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

2、校验

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

为何要校验:

由于符号集存储着文件名、函数名、行号的信息,每一次代码更改后编译符号集也会随之变动,因此要想符号化.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'
复制代码

3、符号化文件

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

一、经过XCode自动符号化Crash文件

二、经过命令行工具symbolicatecrash符号化

4、分析

crash 类型oop

一、EXC_BAD_ACCESS

坏内存访问

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

引发坏内存的 signal 类型

  • SIGSEGV布局

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

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

    致使SIGABRT的错误,由于内存中根本就没有这个空间
    复制代码

僵尸对象解决

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

二、EXC_ARITHETIC

除 0 操做

三、SIGILL

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

四、SIGABRT

SIGABRT表明SIGNAL ABORT(停止信号)。当操做系统发现不安全的状况时,它可以对这种状况进行更多的控制;必要的话,它能要求进程进行清理工做。在调试形成此信号的底层错误时,并无什么妙招

通常表示内存根本没这个空间
复制代码

五、SIGBUS

内存未对齐
复制代码

五、watchdog 超时

在iOS上,它常常出如今执行一个同步网络调用而阻塞主线程的状况。所以,永远不要进行同步网络调用。
复制代码

5、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);
复制代码
相关文章
相关标签/搜索