iOS Crash收集与分析详解(基础篇)

前言:

最近测试妹子老是抱怨我偶现的Bug不好复现,我这边出于偷懒(其实是工作很忙)一直再说不能复现Bug的妹子不是好测试,最近闲下来了,正好谈谈Crash的收集和分析。

一、Crash收集

噔噔噔噔~万能的官方文档又出现了,先上地址
Understanding and Analyzing Application Crash Reports

Crash收集与解析流程图

通过上图我们可以发现Crash的收集主要有两种方式。

1、使用Xcode从设备获取崩溃日志:

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


崩溃的Log

2、通过设备直接获取崩溃日志(此处以最新版iOS11为例,其他版本可能有些许不同)

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


官方文档的友情提醒

3、苹果爸爸审核时候给你发的.crash文件(手动滑稽)

What the fuck??面对一大串的16进制数字你可能会感到一脸懵逼,莫惊慌,如果你仔细的看了看官方文档,你就会发现收集Crash的Log是一件很轻松的事情,然而分析Crash却并不是那么容易的事情(看完这篇文章后你会发现也很容易!!!!)
我们能把16进制数字转换成能看懂的东西么?当然可以,这个时候就需要理解dSYM符号集,细心的小伙伴在看第一张Crash流程图中可能已经发现.xcarchive文件中包含了.dSYM文件。


dSYM符号集:

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

符号集的生成与获取:

  • 符号集在Organizer中选中打包的Archive->Show in Finder中选中Archive,右键显示包内容下的dSYMs文件夹下(或者点击Organizer右边的Download dSYM,XCode会从App Store下载该文件并插入到此Archive中)。
  • 如果在Debug模式下,找到项目的Build Settings
    Debug Infomatiion Format设置成DWARF with dSYM file
    并把Generate Debug Symbols置为YES
    然后编译,在项目文件夹Products中找到.app文件右击Show in Finder找到dSYM文件
    Xcode设置图

看到这里你可能已经知道,通过dSYM中存储的信息可以把crash日志中的16进制数字一一对应成我们看得懂的文件名、函数名和行号,这个过程就叫做符号化,那么如何做呢?

二、校验文件

在符号化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'
6C449B5E-031D-493C-A094-B8507AB0B4CE.png

比如上图能看到三者的UUID都是一致的,可以安心去符号化文件啦。

三、符号化文件

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

1)如果本地存在.crash对应的.dSYM文件,则直接到上文中(1、使用Xcode从设备获取崩溃日志:)到View Device Logs这步,把文件拖入右边的logs列表,Xcode会自动去符号化文件,如果满眼都是16进制数字的化,点击Re-Symbolicate Log即可

符号化后的crash日志

2)如果此时本地的Archive文件已经被你删除,需要把上述两个文件放入同一目录下(全英文目录),如果.dSYM你并没有备份,则需要回到crash日志对应的版本重新打包(论版本控制的重要性!),重复1)的步骤也可以得到符号化的日志。

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

如果你不想用Xcode去符号化,你也可以通过symbolicatecrash来手动符号化crash日志,symbolicatecrash是Xcode下的一个工具。
1)首先先找到这个工具,我们通过Spotlight搜索找到symbolicatecrash并复制到桌面的CrashSignifying文件夹中,在这个文件夹下同样放入.crash、.dSYM文件。
2)打开终端,进入你刚才创建的CrashSignifying文件夹中,输入命令行

export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer​

然后在输入

./symbolicatecrash /Users/你的电脑用户名/Desktop/CrashSignifying/xxx(崩溃日志名字).crash /Users/你电脑的用户名/Desktop/CrashSignifying/xxxx(dSYM文件名字).dSYM > Symbol_Crash.crash

如果报No such file or directory : at ./symbolicatecrash line 909.错误,尝试执行

./symbolicatecrash ./*.crash ./*.app.dSYM>Symbol_Crash.crash

这样crash文件就被符号化完成了,打开符号化如下图:
可以清楚的看到最后调用的堆栈信息

四、Crash分析

以上图为例,大部分字段都是不言而喻的,下面列举一些有用处的。(在官方文档都有解释,这里做归纳与翻译)

Incident Identifier: 报告的唯一标识符,两份报告决不会共享同一个事件标识符。
CrashReporter Key:每个设备的匿名标识符,来自同一设备的两个报告将包含相同的值。
Process:很明显是我们的进程名称。
Date/Time 与 Launch Time:报告生成时间与程序开始运行时间
Exception Type:异常类型
Exception Note:不属于异常类型的附加信息,如果这个字段包含SIMULATED(不是崩溃),那这个进程不是崩溃的,而是在系统的请求下被杀死,通常是看门狗机制起了作用(APP内一段时间内无法响应用户的操作,会被系统kill)。

接着是最重要的堆栈信息,由下到上为最后调用的顺序:

屏幕快照 2018-03-23 10.07.34.png

可以很明显的看到,一个名为ViewController的对象在viewDidLoad方法中调用了第35行的testMethodTwo方法,并执行testMethodTwo方法中的61行时代码,在Backtrace第2行可以发现调用了未识别的方法导致崩溃,我们来看下代码。
testMethodTwo方法

最终我们找到了崩溃的原因:一个NSArray调用了addObject方法,so easy!

一些较常见的异常类型(如果翻译错误请指正):

内存访问不良[EXC_BAD_ACCESS // SIGSEGV // SIGBUS]

通常用于访问了不该访问的内存导致或者尝试以不允许的方式访问内存(例如只读属性,比如在上一篇我们提到的通过KVO更改只读属性),并且" Exception SubType"字段会包含kern_return_t来描述错误和未正确访问的内存地址。
下面是官方给出的建议:

  • 如果objc_msgSendobjc_release接近崩溃线程的Backtraces(堆栈信息回溯)的顶部,则该进程可能试图向释放的对象发送消息,可以使用Zombie Instrument来分析应用程序,以更好地了解此次崩溃的情况。
  • 如果gpus_ReturnNotPermittedKillClient接近崩溃线程的Backtraces的顶部,则该进程被终止,因为它尝试在后台使用OpenGL ES或Metal进行渲染。
异常退出[EXC_CRASH // SIGABRT]

该进程异常退出,此异常类型崩溃的最常见原因是向对象发送了无法识别的消息,比如上文中向NSArray发送了addObject消息。
另外如果App Extensions需要太多时间来初始化(看门狗机制),那么App Extensions将终止于此异常类型,如果扩展因启动时挂起而死亡,则生成的崩溃报告的Exception Subtype将会是LAUNCH_HANG,由于扩展没有main函数,任何花在初始化上的时间都会在+load扩展库和相关库中的静态构造函数和方法中,你应该尽可能多地推迟这项工作。

资源限制[EXC_RESOURCE]

该过程超出了资源消耗限制,这是来自操作系统的通知,该进程正在使用太多的资源,确切的资源列在Exception SubType字段中。如果Exception Note字段包含NON-FATAL CONDITION,则即使生成崩溃报告,该进程也不会被终止。

  • 异常子类型MEMORY表示该进程已超过系统施加的内存限制。
  • 异常子类型WAKEUPS表示进程中的线程每秒被唤醒的次数过多,这迫使CPU醒来的频率很高,并且消耗电池寿命。

五、总结

文章写了一半开始忙了起来,第三第四节的内容现在才补上来(已经三天过去啦),如果能给小伙伴带来一点帮助,那我就很开心了,咱们下周再见。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 序 在日常开发中,app难免会发生崩溃。简单的崩溃还好说,复杂的崩溃就需要我们通过解析Crash文件来分析了,解析...
    Mr_Baymax阅读 2,461评论 0 2
  • 如果大家是用真机在调试的过程中出现了Crash,那么请看iOS调试之 crash log分析 前言 导读:Unde...
    KODIE阅读 6,462评论 7 12
  • Apple Develop官方原文:Understanding and Analyzing Application...
    iDeveloper阅读 5,435评论 1 9
  • 前言 iOS崩溃是让iOS开发人员比较头痛的事情,app崩溃了,说明代码写的有问题,这时如何快速定位到崩溃的地方很...
    齐滇大圣阅读 65,222评论 29 443
  • 该文章属于刘小壮原创,转载请注明:刘小壮[https://www.jianshu.com/u/2de707c93d...
    刘小壮阅读 37,494评论 45 122