当一个应用程序在一台iOS 设备上崩溃时,一份“崩溃报告”将在该设备上次创建并存储起来。崩溃报告描述应用程序是在何种条件下崩溃的,大部分情况下包含一份当前正在运行线程的完整的堆栈跟踪。
产生崩溃日志的原因:
- 应用违反操作系统规则,包括在启动、恢复、挂起、退出时watchdog超时、用户强制退出和低内存终止等。
- 应用中有Bug
从多任务窗口中终止一个暂停的应用程序不会产生崩溃日志。一旦一个应用被暂停,它有资格被iOS在任何时间终止,因此不会产生崩溃日志。

- 本机通过Xcode的Devices窗口获取某个设备的崩溃日志
- 设备与电脑上的iTunes Store同步后,会将崩溃日志保存在电脑上
- 应用提交到App Store后,可通过itunes connect后台获取到用户上报的Crash日志。
- 有很多优秀的第三方Crash收集系统大大的方便了我们收集Crash,甚至还带了符号化Crash日志的功能。比较常用的有Crashlytics,Flurry等。

1.Process Information
Incident Identifier: 66AFBBF0-7ACB-4319-97C7-6F44E09FF9EB //崩溃报告的唯一标识符 CrashReporter Key: 97aec51145730a778c0d1cfdfc17c1b8c86ba4c5 //设备标识相对应的唯一键值(并非真正的设备的UDID,为保护隐私iOS6以后已无法获取) Hardware Model: iPad5,3 //发生Crash的设备类型 Process: XXXXClient [407] //Crash的进程名称,通常都是我们的App的名字, []里面是当时进程的ID Path: /private/var/mobile/Containers/Bundle/Application/0380D606-3A40-4633-A1B2-7E1F3E3D4FCA/XXXXClient.app/XXXXClient //可执行程序在手机上的存储位置,注意路径时到x.app/x,x.app其实是作为一个Bundle的,真正的可执行文件其实是Bundle里面的x Identifier: com.xxxx.myapp //App的Indentifier,通常为“com.xxx.yyy” Version: 1 (1.0.0) //App的版本号,由Info.plist中 CFBundleShortVersionString + CFBundleVersion Code Type: ARM-64 (Native) //App的CPU架构 Parent Process: launchd [1] //当前进程的父进程,由于iOS中App通常都是单进程的,一般父进程都launchd
2.Basic Information
Date/Time: 2016-02-19 00:34:43.449 -0800 //Crash发生的时间 Launch Time: 2016-02-19 00:34:43.399 -0800 OS Version: iOS 8.4 (12H143) //系统版本,括号内的数字代表的时Bulid号 Report Version: 105 //Crash日志的格式
3.Exception
Exception Type: EXC_CRASH (SIGABRT) //异常类型 Exception Subtype: //v104 Exception Codes: 0x0000000000000000, 0x0000000000000000 //v105 Triggered by Thread: 0 //v105 Crashed Thread //v104
4.Thread Backtrace
发生Crash的线程的Crash调用栈,从上到下分别代表调用顺序,最上面的一个表示抛出异常的位置,依次往下可以看到API的调用顺序。
Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Crashed: //编号 二进制库名 调用方法的地址 基本地址 + 偏移 0 libsystem_kernel.dylib 0x0000000194b3b270 __pthread_kill + 8 1 libsystem_pthread.dylib 0x0000000194bd916c pthread_kill + 108 2 libsystem_c.dylib 0x0000000194ab2b14 abort + 108 3 ...g_rt.asan_ios_dynamic.dylib 0x00000001032756d0 0x103224000 + 333520 4 ...g_rt.asan_ios_dynamic.dylib 0x000000010326955c 0x103224000 + 283996 5 ...g_rt.asan_ios_dynamic.dylib 0x000000010326cf28 0x103224000 + 298792 6 ...g_rt.asan_ios_dynamic.dylib 0x0000000103269640 0x103224000 + 284224 7 ...g_rt.asan_ios_dynamic.dylib 0x000000010326d0e8 0x103224000 + 299240 8 ...g_rt.asan_ios_dynamic.dylib 0x000000010325ef50 0x103224000 + 241488 9 ...g_rt.asan_ios_dynamic.dylib 0x0000000103268d18 0x103224000 + 281880 10 dyld 0x00000001200b9234 ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 256 11 dyld 0x00000001200b93ec ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 32 12 dyld 0x00000001200b5688 ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 328 13 dyld 0x00000001200b561c ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 220 14 dyld 0x00000001200b54d8 ImageLoader::processInitializers(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) + 136 15 dyld 0x00000001200b57a0 ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) + 80 16 dyld 0x00000001200aa150 dyld::initializeMainExecutable() + 196 17 dyld 0x00000001200ad8bc dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) + 2664 18 dyld 0x00000001200a9040 _dyld_start + 64
5.Thread State
Crash时发生时刻,线程的状态(寄存器中的值)
Thread 0 crashed with ARM Thread State (64-bit): x0: 0x0000000000000000 x1: 0x0000000000000000 x2: 0x0000000000000000 x3: 0x0000000000010000 x4: 0x000000000000027b x5: 0x0000000000000000 x6: 0x0000000000000000 x7: 0x0000000000000250 x8: 0x0000000008000000 x9: 0x0000000004000000 x10: 0x0000000000000000 x11: 0x0000000000000018 x12: 0x0000000000000001 x13: 0x0000000000062aa8 x14: 0x0000000000000015 x15: 0x0000000000000000 x16: 0x0000000000000148 x17: 0x0000000000000000 x18: 0x0000000000000000 x19: 0x0000000000000006 x20: 0x0000000198ae4310 x21: 0x0000000103280963 x22: 0x0000000000000000 x23: 0x0000000000000000 x24: 0x0000000000000093 x25: 0x000000016fd182d8 x26: 0x00000001200d8d11 x27: 0x000000010328c000 x28: 0x00000001032243d0 fp: 0x000000016fd17920 lr: 0x0000000194bd9170 sp: 0x000000016fd17900 pc: 0x0000000194b3b270 cpsr: 0x00000000
6.Binary Images
Crash时刻App加载的所有的库,其中第一行是Crash发生时我们App可执行文件的信息,可以看出为armv7,可执行文件的包得uuid位c0f……cd65,解析Crash的时候dsym文件的uuid必须和这个一样才能完成Crash的符号化解析。
Binary Images: 0x1000e4000 - 0x101fdffff XXXClient arm64 <aa8ef7e9f9c43c7c87f4f75cf266d479> /var/mobile/Containers/Bundle/Application/0380D606-3A40-4633-A1B2-7E1F3E3D4FCA/XXXXClient.app/XXXXClient 0x103224000 - 0x103287fff libclang_rt.asan_ios_dynamic.dylib arm64 <c51061e5b8443a8e9b6c2b76628b4b95> /var/mobile/Containers/Bundle/Application/0380D606-3A40-4633-A1B2-7E1F3E3D4FCA/XXXX.app/Frameworks/libclang_rt.asan_ios_dynamic.dylib 0x1200a8000 - 0x1200cffff dyld arm64 <de589e6153453237a6cf724cb236d83c> /usr/lib/dyld 0x1810ac000 - 0x181240fff AVFoundation arm64 <b9c4b32ba43a3a798c4adcaad3608f52> /System/Library/Frameworks/AVFoundation.framework/AVFoundation 0x181244000 - 0x1812a8fff libAVFAudio.dylib arm64 <6667f63f0f1635668dc941d6b79062e1> /System/Library/Frameworks/AVFoundation.framework/libAVFAudio.dylib 0x194bf0000 - 0x194bf5fff libunwind.dylib arm64 <8b87982b31ad3569a95e75457cadba3e> /usr/lib/system/libunwind.dylib 0x194bf8000 - 0x194c1bfff libxpc.dylib arm64 <c9f3c08a8a3b3849a905d24911240853> /usr/lib/system/libxpc.dylib
符号化
包含堆栈跟踪的崩溃报告需要先进行符号化(symbolicated)才可以进行分析。符号化的过程是将内存地址替换为便于人们阅读的函数名称和行号。假如你通过Xcode的Organizer窗口获取崩溃日志,那么该报告将在几秒钟后自动进行符号化。否则你需要将.crash文件导入到Xcode的Organizer进行符号化。
//符号化前 6 Rage Masters 0x0001625c 0x2a000 + 3003 //符号化后 6 Rage Masters 0x0001625c -[RMAppDelegate application:didFinishLaunchingWithOptions:] (RMAppDelegate.m:35)
一个完整的Sample
打开Crash Log 会看到如下的信息: Incident Identifier: AF4F2C83-8F68-47EF-B5AA-F16B067B5DF4 CrashReporter Key: 5670de85ee1f0f3c904891536e81ec086ed4b35b Hardware Model: iPhone8,1 Process: kidneyUser [896] Path: /private/var/containers/Bundle/Application/48C71AA1-EB99-49B1-ABD7-2903DBA8E394/kidneyUser.app/kidneyUser Identifier: kidneyDiseaseHospitalUser Version: 1 (1.0) Code Type: ARM-64 (Native) Parent Process: launchd [1] Date/Time: 2016-05-05 10:45:43.43 +0800 Launch Time: 2016-05-05 10:42:07.07 +0800 OS Version: iOS 9.3.1 (13E238) Report Version: 105 Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Exception Note: EXC_CORPSE_NOTIFY Triggered by Thread: 0 Filtered syslog: None found Last Exception Backtrace: 0 CoreFoundation 0x181aeee38 __exceptionPreprocess + 124 1 libobjc.A.dylib 0x181153f80 objc_exception_throw + 56 2 CoreData 0x18393ab44 -[NSManagedObjectModel initWithContentsOfURL:] + 856 3 kidneyUser 0x1002b81d8 0x1000d8000 + 1966552 4 kidneyUser 0x1002b82dc 0x1000d8000 + 1966812 5 kidneyUser 0x1002b86a0 0x1000d8000 + 1967776 6 kidneyUser 0x1002b87cc 0x1000d8000 + 1968076 7 kidneyUser 0x1002b8024 0x1000d8000 + 1966116 8 UIKit 0x186cc9128 -[UIApplication _terminateWithStatus:] + 280 9 UIKit 0x186ee7f08 __102-[UIApplication _handleApplicationDeactivationWithScene:shouldForceExit:transitionContext:completion:]_block_invoke2017 + 796 10 UIKit 0x186eeafd8 _runAfterCACommitDeferredBlocks + 292 11 UIKit 0x186ef8990 _cleanUpAfterCAFlushAndRunDeferredBlocks + 92 12 UIKit 0x186c2a4a4 _afterCACommitHandler + 96 13 CoreFoundation 0x181aa47b0 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32 14 CoreFoundation 0x181aa2554 __CFRunLoopDoObservers + 372 15 CoreFoundation 0x181aa2984 __CFRunLoopRun + 928 16 CoreFoundation 0x1819ccd10 CFRunLoopRunSpecific + 384 17 GraphicsServices 0x1832b4088 GSEventRunModal + 180 18 UIKit 0x186ca1f70 UIApplicationMain + 204 19 kidneyUser 0x1002c71e8 0x1000d8000 + 2028008 20 libdyld.dylib 0x18156a8b8 start + 4 Global Trace Buffer (reverse chronological seconds): 2.434148 AppleJPEG 0x000000018354ea88 [0x12e203600] Releasing session Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Crashed: 0 libsystem_kernel.dylib 0x000000018168811c __pthread_kill + 8 1 libsystem_pthread.dylib 0x0000000181754ef8 pthread_kill + 112 2 libsystem_c.dylib 0x00000001815f9dac abort + 140 3 libc++abi.dylib 0x000000018112d3f4 __cxa_bad_cast + 0 4 libc++abi.dylib 0x0000000181149e98 default_unexpected_handler() + 0 5 libobjc.A.dylib 0x0000000181154248 _objc_terminate() + 124 6 libc++abi.dylib 0x0000000181146f44 std::__terminate(void (*)()) + 16 7 libc++abi.dylib 0x0000000181146b10 __cxa_rethrow + 144 8 libobjc.A.dylib 0x0000000181154120 objc_exception_rethrow + 44 9 CoreFoundation 0x00000001819ccdb8 CFRunLoopRunSpecific + 552 10 GraphicsServices 0x00000001832b4088 GSEventRunModal + 180 11 UIKit 0x0000000186ca1f70 UIApplicationMain + 204 12 kidneyUser 0x00000001002c71e8 0x1000d8000 + 2028008 13 libdyld.dylib 0x000000018156a8b8 start + 4 以上就是Crash Log 文件的信息(设备的信息, crash信息,异常信息, 线程信息) 1. 设备信息 Incident Identifier: AF4F2C83-8F68-47EF-B5AA-F16B067B5DF4 // crash的ID CrashReporter Key: 5670de85ee1f0f3c904891536e81ec086ed4b35b // crash 的设备ID Hardware Model: iPhone8,1 // 手机的型号 (iPhone8,1代表iPhone6s 8,2 代表iPhone6s Plus) Process: kidneyUser [896] // App的名称 (该App的进程ID) Path: /private/var/containers/Bundle/Application/48C71AA1-EB99-49B1-ABD7-2903DBA8E394/kidneyUser.app/kidneyUser // APP 的位置 路径 Identifier: kidneyDiseaseHospitalUser // bundle ID Version: 1 (1.0) // APP的版本号 Code Type: ARM-64 (Native) // app的应用架构 Parent Process: launchd [1] Date/Time: 2016-05-05 10:45:43.43 +0800 // crash发生的时间 Launch Time: 2016-05-05 10:42:07.07 +0800 // 进入应用的时间 OS Version: iOS 9.3.1 (13E238) // iOS系统的版本 Report Version: 105 2.异常信息 Exception Type: EXC_CRASH (SIGABRT) // 异常的类型 Exception Codes: 0x0000000000000000, 0x0000000000000000 // 异常出错的代码 Exception Note: EXC_CORPSE_NOTIFY // 异常通知 Triggered by Thread: 0 // 异常发生的线程(0代表主线程, 其他为主线程) 补充常见的Exception Codes代码类型 Exception Codes: 常见代码有以下几种 0x8badf00d错误码:Watchdog超时,意为“ate bad food”。 0xdeadfa11错误码:用户强制退出,意为“dead fall”。 0xbaaaaaad错误码:用户按住Home键和音量键,获取当前内存状态,不代表崩溃。 0xbad22222错误码:VoIP应用(因为太频繁?)被iOS干掉。 0xc00010ff错误码:因为太烫了被干掉,意为“cool off”。 0xdead10cc错误码:因为在后台时仍然占据系统资源(比如通讯录)被干掉,意为“dead lock” 补充常见的Exception Type异常类型的信息: 1.EXC_BAD_ACCESS:此类型是最常见的crash, 通常用于访问了不该访问的内存导致的,一般 EXC_BAD_ACCESS后面的()还会带有补充信息 SIGSEGV:通常由于重复释放对象导致, 一般在ARC以后很少见到 SIGABRT: 收到Abort信号退出, 通常Foundtion库中的容器为了保护状态正常会做一些检测, 例如插入nil到数据中等会遇到此类错误. 野指针错误形式在Xcode中通常表现为:Thread 1:EXC_BAD_ACCESS(code=EXC_I386_GPFLT)错误。因为你访问了一块已经不属于你的内存。 SEGV(Segmentation Violation): 代表无效内存地址, 比如空指针, 未初始化指针, 栈溢出等. SIGBUS:总栈错误, 与SIGSEGV不同的是, SIGSEGV访问的是无效的地址, 而SIGBUS访问的是有效的地址, 但是总栈访问异常(如地址对齐问题) SIGILL: 尝试执行非法的指令, 可能不被识别或者没有权限 SIGFPE: 数学计算相关问题, 比如除零操作 SIGIPIPE: 管道另一端没有进程接手数据 2. EXC_BAD_INSTRUCTION:此类异常通常由于线程执行非法指令导致 3. EXC_ARITHMETIC:除零错误会抛出此类异常 Last Exception Backtrace: 最后异常回溯, 一般根据这个代码就能找到具体的crash问题 下面截取的是微信的crash blog Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0: 0 libsystem_kernel.dylib 0x000000018223ff24 __psynch_cvwait + 8 1 libsystem_pthread.dylib 0x000000018230ad20 _pthread_cond_wait + 704 2 Foundation 0x0000000182f9fdf0 -[NSCondition waitUntilDate:] + 344 3 Foundation 0x0000000182f9ce34 -[NSConditionLock lockWhenCondition:beforeDate:] + 256 4 UIKit 0x000000018781dbc4 -[UIKeyboardTaskQueue waitUntilAllTasksAreFinished] + 196 5 UIKit 0x0000000187c05878 -[UIKeyboardImpl setKeyboardInputMode:userInitiated:] + 112 6 UIKit 0x0000000187c0de44 -[UIKeyboardImpl recomputeActiveInputModesWithExtensions:] + 336 7 UIKit 0x000000018781e8f0 -[UIKeyboardImpl setDelegate:force:] + 2292 8 UIKit 0x0000000187817eb0 -[UIPeripheralHost(UIKitInternal) _reloadInputViewsForResponder:] + 1180 9 UIKit 0x00000001878179e4 -[UIResponder(UIResponderInputViewAdditions) reloadInputViews] + 80 10 UIKit 0x0000000187879670 -[UIResponder becomeFirstResponder] + 600 11 UIKit 0x0000000187879a1c -[UIView(Hierarchy) becomeFirstResponder] + 148 12 UIKit 0x0000000187900b34 -[UITextField becomeFirstResponder] + 64 13 UIKit 0x00000001879b1fe4 -[UITextInteractionAssistant(UITextInteractionAssistant_Internal) setFirstResponderIfNecessary] + 256 14 UIKit 0x00000001879b1498 - 我们可以看到发生Crash的线程的Crash调用栈, 从上到下分别代表调用顺序, 最上面的一个表示抛出异常的位置, 一次往下可以看到API调用顺序, 上图的信息表明本次Crash出现在[NSCondition waitUntilDate:]这个方法中(后面加的数值 我猜应该是地址偏移量O(∩_∩)O) 大概可以找到crash的具体原因(某个文件中的某个方法), 这样问题就浮出水面了, 方便产品上线后版本迭代, 修改BUG.