14年记录于有道笔记的老文章,有时间再修改。
什么是崩溃日志?
一个App启动之后,用着用着就突然被iOS系统关闭,或者干脆就起不来,在打开的一瞬间关闭,这就是Crash,俗称“闪退”“崩溃”。
iOS设备上的应用闪退时,操作系统会生成一个扩展名为crash的日志文件,这个文件会保存的特定系统目录下。
崩溃日志上有很多有用的信息,上面有每个正在执行线程的完整堆栈跟踪信息,所以你能从中了解到闪退发生时各线程都在做什么,并分辨出闪退发生在哪个线程上和相关的原因。
从哪里能得到它?
设备与电脑上的iTunes Store同步后,会将崩溃日志保存在电脑上。根据电脑操作系统的不同,崩溃日志将保存在以下位置:
Mac OSX:~/Library/Logs/CrashReporter/MobileDevice/
Windows XP: C:Documents and Settings
Application DataApple ComputerLogsCrashReporterMobileDevice Windows Vista or 7: C:Users
AppDataRoamingApple ComputerLogsCrashReporterMobileDevice
当用户抱怨闪退时,你可以要求他让设备与iTunes同步,并根据操作系统的不同,到上述位置把崩溃日志下载下来,然后通过电子邮件发送给你。
你必需尽量获取用户设备生成的所有崩溃日志。因为崩溃日志越多,就越容易诊断问题所在!
将iOS设备连接到电脑上,然后打开Xcode。从菜单栏上选择 Window
菜单, 然后选择 Devices
,在左侧的导航面板上,点击View Device Logs
查看设备的日志,然后查看你对应的appname的日志。
应用提交到App Store后,你也能从 iTunes Connect 获取到用户的崩溃日志. 登录到 iTunes Connect 上, 选择Manage Your Applications
, 点击相应的应用, 点击应用图标下面的View Details
按钮, 然后点击右栏Links部分的Crash Reports
。
如果应用还卖得不多,或者刚上架不久,或者用户关闭了上传日志的选项,iTunes Connect账号上也可能还没有任何崩溃日志。
什么情况下会产生崩溃日志?
应用违反操作系统规则
从iOS 4.x开始,退出应用时,应用不会立即终止,而是退到后台。但是,如果你的应用响应不够快,操作系统有可能会终止你的应用,并产生一个崩溃日志。这些事件与下列UIApplicationDelegate方法相对应:
application:didFinishLaunchingWithOptions:
applicationWillResignActive:
applicationDidEnterBackground:
applicationWillEnterForeground:
applicationDidBecomeActive:
applicationWillTerminate:
上面所有这些方法,应用只有有限的时间去完成处理。如果花费时间太长,操作系统将终止应用。
注意: 如果你没有把需要花费时间比较长的操作(如网络访问)放在后台线程上就很容易发生这种情况。
iOS 4.x开始支持多任务。如果应用阻塞界面并停止响应,用户可以通过在主屏幕上双击Home按钮来终止应用。此时,操作应用将生成一个崩溃日志。
注意: 双击Home按钮后,你将看到运行过的所有应用。那些应用不一定是正在运行,也不一定是被挂起。通常,用户点击Home按钮时,应用将在后台保留约10分钟,然后操作系统自动将其终止。 所以双击Home按钮显示的应用列表只是表明那是一系列过去打开过的应用。删除那些应用的图标不会产生任何崩溃日志。
在前台运行的应用拥有访问和使用内存的最高优化级。然而,这并不意味着该应用能使用设备的所有可用内存 ——每个应用只能使用一部分可用内存。
当内存使用达到一定程度时,操作系统将发出一个 UIApplicationDidReceiveMemoryWarningNotification 通知。同时,调用 didReceiveMemoryWarning 方法。
此时,为了让应用继续正常运行,操作系统开始终止在后台的其他应用以释放一些内存。所有后台应用被终止后,如果你的应用还需要更多内存,操作系统会将你的应用也终止掉,并产生一个崩溃日志。而在这种情况下被终止的其他后台应用,不会产生崩溃日志。
应用中有Bug
大多数闪退都是由于应用中有Bug,比如调用用了Objective-C对象根本不支持的方法(发送消息),非法内存访问,数组越界,参数不符合要求等。
这些问题在调试阶段,我们都可以很容易的通过断点和console中提供的信息快速定位并解决。
但对于已发布的App,如果想重现并利用上述办法来解决,恐怕会比较费时费事。
最有帮助最直接的办法就是根据出现问题时的闪退日志,分析和判断crash的原因,快速准确的定位和解决。
崩溃日志示例
|
|
进程信息
Incident Identifier 是崩溃报告的唯一标识符。
CrashReporter Key 是与设备标识相对应的唯一键值。虽然它不是真正的设备标识符,但也是一个非常有用的情报:如果你看到100个崩溃日志的CrashReporter Key值都是相同的,或者只有少数几个不同的CrashReport值,说明这不是一个普遍的问题,只发生在一个或少数几个设备上。
Hardware Model 是标识设备类型。 如果很多崩溃日志都是来自相同的设备类型,说明应用只在某特定类型的设备上有问题。上面的日志里,崩溃日志产生的设备是iPhone 4s。
Process 是应用名称。中括号里面的数字是闪退时应用的进程ID。
Identifier 是应用标识符,即bundle identifier。
Version 是应用版本信息,前面是build code,后面是发布版本号。
基本信息
这部分给出了一些基本信息,包括闪退发生的日期和时间,设备的iOS版本。如果有很多崩溃日志都来自iOS 6.0,说明问题只发生在iOS 6.0上。
异常信息
在这部分,你可以看到闪退发生时抛出的异常类型。还能看到异常编码和抛出异常的线程。根据崩溃报告类型的不同,在这部分你还能看到一些另外的信息。
线程回溯
这部分提供应用中所有线程的回溯日志。 回溯是闪退发生时所有活动帧清单。它包含闪退发生时调用函数的清单。看下面这行日志:
|
|
它包括四列:
- 模块号:这里是13
- 二进制库名:这里是LiuLianCustomer
- 调用方法的地址:这里是0x000dbfe6
- 第四部分分为两列,基地址和偏移地址。此处基地址为0x7f000,偏移地址为380902。基地址指向crash的模块(也是模块的load地址)如UIKit。偏移地址指向crash代码的行数。
动态库信息
这些信息包括动态库名称、UUID、模块起始地址、模块结束地址、指令集种类、安装路径等信息。
符号化Symbolication
第一次看到崩溃日志上的回溯时,你或许会觉得它没什么意义。我们习惯使用方法名和行数,而非像这样的神秘位置:
|
|
将这些十六进制地址转化成方法名称和行数的过程称之为符号化。
从Xcode获取崩溃日志后过几秒钟,崩溃日志将被自动符号化。上面那行被符号化后的版本如下 :
|
|
Xcode符号化崩溃日志时,需要访问与App Store上对应的应用二进制文件以及生成二进制文件时产生的 .dSYM 文件,必需完全匹配才行,否则,日志将无法被完全符号化。所以,保留每个分发给用户的编译版本非常重要。
注意: 你必需同时保留应用二进制文件和.dSYM文件才能将崩溃日志完整符号化。每次提交到iTunes Connect的构建都必需归档。.dSYM文件和二进制文件是特定绑定于每一次构建和后续构建的,即使来自相同的源代码文件,每一次构建也与其他构建不同,不能相互替换。
atos就是address to symbol,把地址翻译成符号。是苹果提供的符号化工具,在Mac OS系统下默认安装。
终端下面执行以下命令
|
|
- dysm文件路径:可以在Xcode Organizer的Archives标签栏下找到所有已归档的应用文件。它保存了编译过程的详细信息,其中包括符号信息,路径为 appName.app.dSYM/Contents/Resources/DWARF/appName。
- 模块load地址:模块加载的基地址,可以在日志的动态库信息中找到对应模块的基地址。
- cpu指令集种类:可以为armv6 armv7 armv7s arm64。具体用哪个,可以参考对应模块的动态库信息中确定
- 调用方法地址:想要符号化的地址
symbolicatecrash是Xcode自带的一个分析工具,可以通过机器上的崩溃日志和应用的.dSYM文件定位发生崩溃的位置,把crash日志中的地址替换成代码相应位置。
使用方法:
软链接symbollicatecrash到/usr/bin/中,就可以直接使用sybollicatecrash命令
|
|
设置xcode DEVELOPER_DIR,把下面的内容加入到.bash_profile中即可
|
|
符号化崩溃日志(不需要.app文件,符号文件和crash文件也可以不在同一目录)
|
|
使用dwarfdump验证xxx.crash、xxx.app和xxx.dSYM三者的uuid是否一致。
|
|
|
|
crash文件在动态链接库部分查看对应的UUID,,三者UUID一致才能符号化崩溃日志。
|
|