看懂 Crash 日志
Crash 頭部信息
Incident Identifier:每個(gè) Crash 生成的唯一的 uuid.
CrashReporter Key:CrashReporter 的 uuid, 如果自己捕獲日志,這個(gè)可以忽略慨飘。
Hardware Model:機(jī)型
Process:進(jìn)程名和進(jìn)程ID
Path:進(jìn)程的可執(zhí)行文件路徑
Identifier:Info.plist 中配置的 CFBundleIdentifier 值
Version: CFBundleVersion (CFBundleVersionShort) 即應(yīng)用的Build號(hào)+版本號(hào)
Code Type:機(jī)型的 CPU 架構(gòu)芋膘,但是不是詳細(xì)的架構(gòu)名芬为。比如 arm64e 在這里也是 ARM-64
Parent Process:父進(jìn)程和進(jìn)程ID
Data/Time: Crash發(fā)生的具體時(shí)間唠梨。
Launch Time: 進(jìn)程啟動(dòng)時(shí)間
OS Version: iOS 系統(tǒng)版本和 build號(hào)
Report Version: Crash日志格式的版本號(hào)封豪,一般是 104炫隶。如果這個(gè)version偏高洞辣,用系統(tǒng)的symbolicatecrash命令不能符號(hào)化日志叉存,一般如果看到是204码俩, 改成104之后用symbolicatecrash就可以符號(hào)化了
Crash 異常碼
在 Crash 頭部信息之下, 會(huì)有個(gè)段記錄了 Crash 異常碼。類(lèi)似下圖:
這里我們應(yīng)該關(guān)注:
Exception Type:異常碼歼捏,一般格式是 Mach異常碼 ( UNIX 信號(hào)類(lèi)型 )
Exception Subtype:一般情況里面帶的是 Mach異常的 subcode, 還有 Crash 相關(guān)地址信息稿存。
Triggered by Thread:發(fā)生Crash的線(xiàn)程,大部分情況到這個(gè)線(xiàn)程的堆棧里面去看 Crash 堆棧瞳秽。
Application Specific Information:如果是 Objc/c++ Exception 異常瓣履,這里是異常的信息,這個(gè)是定位異常的關(guān)鍵信息
Last Exception Backtrace:拋出異常的代碼堆棧, 如果是 Objc/c++ Exception 異常造成的 Crash练俐,就看這個(gè)堆棧袖迎,Crashed Thread: 里的堆棧是 abort(),沒(méi)有意義腺晾。
附異常碼的解釋, 非所有異常碼燕锥,只是我們 Crash 中可能會(huì)看到的 :
Mach 異常 | 簡(jiǎn)介 | 使用場(chǎng)景 |
---|---|---|
EXC_BAD_ACCESS (SIGBUS) | 總線(xiàn)錯(cuò)誤 | 1、內(nèi)存地址對(duì)齊出錯(cuò) 2悯蝉、試圖執(zhí)行沒(méi)有執(zhí)行權(quán)限的代碼地址 |
SIGSEGV | 段錯(cuò)誤 | 1归形、訪問(wèn)未申請(qǐng)的虛擬內(nèi)存地址 2、沒(méi)有寫(xiě)權(quán)限的內(nèi)存寫(xiě)入 |
EXC_BAD_INSTRUCTION (SIGILL) | 非法指令鼻由,即機(jī)器碼指令不正確 | 1, iOS 上偶現(xiàn)的問(wèn)題暇榴,遇到之后用戶(hù)會(huì)連續(xù)閃退厚棵,直到應(yīng)用二進(jìn)制的緩存重新加載 或重啟手機(jī)。此問(wèn)題挺影響體驗(yàn)蔼紧,但是報(bào)給蘋(píng)果不認(rèn)婆硬,因?yàn)樘O(píng)果那邊沒(méi)有收集到,目前沒(méi)有太好辦法奸例。因?yàn)?iOS 應(yīng)用內(nèi)無(wú)法對(duì)一篇內(nèi)存同時(shí)獲取 w+x 權(quán)限的彬犯,因此應(yīng)用無(wú)法造成此類(lèi)問(wèn)題,所以判斷是蘋(píng)果的問(wèn)題哩至。 |
EXC_ARITHMETIC (SIGFPE) | 算術(shù)運(yùn)算出錯(cuò)躏嚎,比如除0錯(cuò)誤 | iOS 默認(rèn)是不啟用的蜜自,所以我們一般不會(huì)遇到菩貌。 |
EXC_SOFTWARE (我們?cè)?Crash 日志中一般不會(huì)看到這個(gè)類(lèi)型,蘋(píng)果的日志里會(huì)是 EXC_CRASH) (SIGSYS) | 系統(tǒng)調(diào)用異常 | 無(wú) |
SIGPIPE | 管道破裂 | 1, Socket通信是可能遇到重荠,如讀進(jìn)程以及終止時(shí)箭阶,寫(xiě)進(jìn)程繼續(xù)寫(xiě)入數(shù)據(jù)。2, 根據(jù)蘋(píng)果的文檔戈鲁,我們可以忽略這個(gè)信號(hào)https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/CommonPitfalls/CommonPitfalls.html |
SIGABRT | abort() 發(fā)生的信號(hào) | 典型的軟件信號(hào)仇参,通過(guò) pthread_kill() 發(fā)送 |
SIGKILL | 進(jìn)程內(nèi)無(wú)法攔截 | 1, exit(), kill(9) 等函數(shù)調(diào)用 2, iOS系統(tǒng)殺進(jìn)程用的,比如 watchDog 殺進(jìn)程 |
EXC_BREAKPOINT | SIGTRAP 由斷點(diǎn)指令或其它trap指令產(chǎn)生 | 部分系統(tǒng)框架里面會(huì)用 __builtin_trap() 來(lái)產(chǎn)生一個(gè) SIGTRAP 類(lèi)型的 Crash |
EXC_GUARD | 文件句柄錯(cuò)誤 | 試圖 close 一個(gè)內(nèi)核的 fd. |
EXC_RESOURCE | 資源受限 | 線(xiàn)程調(diào)度太頻繁婆殿,子線(xiàn)程每秒被喚醒次數(shù)超過(guò)150:https://stackoverflow.com/questions/25848441/app-shutdown-with-exc-resource-wakeups-exception-on-ios-8-gm |
Crash 堆棧
下面一張圖介紹了 Crash 堆棧中每個(gè)段的含義(在網(wǎng)上找的說(shuō)的挺細(xì)):
Signal信號(hào)的類(lèi)型:
- SIGABRT–程序中止命令中止信號(hào)
- SIGALRM–程序超時(shí)信號(hào)
- SIGFPE–程序浮點(diǎn)異常信號(hào)
- SIGILL–程序非法指令信號(hào)
- SIGHUP–程序終端中止信號(hào)
- SIGINT–程序鍵盤(pán)中斷信號(hào)
- SIGKILL–程序結(jié)束接收中止信號(hào)
- SIGTERM–程序kill中止信號(hào)
- SIGSTOP–程序鍵盤(pán)中止信號(hào)
- SIGSEGV–程序無(wú)效內(nèi)存中止信號(hào)
- SIGBUS–程序內(nèi)存字節(jié)未對(duì)齊中止信號(hào)
-
SIGPIPE–程序Socket發(fā)送失敗中止信號(hào)
SIGABRT
就crash而言诈乒,SIGABRT是一個(gè)比較好解決的,因?yàn)樗且粋€(gè)可掌控的crash婆芦。App會(huì)在一個(gè)目的地終止怕磨,因?yàn)橄到y(tǒng)意識(shí)到app做了一些他不能支持的事情。
通常, SIGABRT 異常是由于某個(gè)對(duì)象接收到未實(shí)現(xiàn)的消息引起的消约。 或者肠鲫,用簡(jiǎn)單的話(huà)說(shuō),在某個(gè)對(duì)象上調(diào)用了不存在的方法或粮。
SIGSEGV
SIGSEGV程序無(wú)效內(nèi)存中止信號(hào)导饲,一般是表示內(nèi)存不合法,
SIGBUS
SIGBUS程序內(nèi)存字節(jié)未對(duì)齊中止信號(hào),
補(bǔ)充常見(jiàn)的Exception Codes代碼類(lèi)型
Exception Codes: 常見(jiàn)代碼有以下幾種
0x8badf00d錯(cuò)誤碼:Watchdog超時(shí),意為“ate bad food”氯材。
0xdeadfa11錯(cuò)誤碼:用戶(hù)強(qiáng)制退出渣锦,意為“dead fall”。
0xbaaaaaad錯(cuò)誤碼:用戶(hù)按住Home鍵和音量鍵氢哮,獲取當(dāng)前內(nèi)存狀態(tài)泡挺,不代表崩潰。
0xbad22222錯(cuò)誤碼:VoIP應(yīng)用(因?yàn)樘l繁命浴?)被iOS干掉娄猫。
0xc00010ff錯(cuò)誤碼:因?yàn)樘珷C了被干掉贱除,意為“cool off”。
0xdead10cc錯(cuò)誤碼:因?yàn)樵诤笈_(tái)時(shí)仍然占據(jù)系統(tǒng)資源(比如通訊錄)被干掉媳溺,意為“dead lock”
異常代碼0x8badf00d指示應(yīng)用程序已終止的iOS 因?yàn)榭撮T(mén)狗超時(shí)發(fā)生月幌,應(yīng)用程序時(shí)間太長(zhǎng)、終止悬蔽,或?qū)ο到y(tǒng)時(shí)間作出相應(yīng)扯躺。一個(gè)常見(jiàn)的原因是做在主線(xiàn)程上的同步聯(lián)網(wǎng)。無(wú)論操作是線(xiàn)程0上蝎困,需要搬到后臺(tái)線(xiàn)程录语,或處理方式不同,所以它不會(huì)阻止在主線(xiàn)程禾乘。
補(bǔ)充常見(jiàn)的Exception Type異常類(lèi)型的信息:
1澎埠、EXC_BAD_ACCESS:此類(lèi)型是最常見(jiàn)的crash, 通常用于訪問(wèn)了不該訪問(wèn)的內(nèi)存導(dǎo)致的,一般EXC_BAD_ACCESS后面的()還會(huì)帶有補(bǔ)充信息
野指針錯(cuò)誤形式在Xcode中通常表現(xiàn)為:Thread 1:EXC_BAD_ACCESS(code=EXC_I386_GPFLT)錯(cuò)誤。因?yàn)槟阍L問(wèn)了一塊已經(jīng)不屬于你的內(nèi)存始藕。
2蒲稳、SIGSEGV:通常由于重復(fù)釋放對(duì)象導(dǎo)致, 一般在ARC以后很少見(jiàn)到
3、SIGABRT: 收到Abort信號(hào)退出, 通常Foundtion庫(kù)中的容器為了保護(hù)狀態(tài)正常會(huì)做一些檢測(cè), 例如插入nil到數(shù)據(jù)中等會(huì)遇到此類(lèi)錯(cuò)誤.
4伍派、SEGV(Segmentation Violation):代表無(wú)效內(nèi)存地址, 比如空指針, 未初始化指針, 棧溢出等.
5江耀、SIGBUS:總棧錯(cuò)誤, 與SIGSEGV不同的是, SIGSEGV訪問(wèn)的是無(wú)效的地址, 而SIGBUS訪問(wèn)的是有效的地址, 但是總棧訪問(wèn)異常(如地址對(duì)齊問(wèn)題)
6、SIGILL: 嘗試執(zhí)行非法的指令, 可能不被識(shí)別或者沒(méi)有權(quán)限
7诉植、SIGFPE: 數(shù)學(xué)計(jì)算相關(guān)問(wèn)題, 比如除零操作
8祥国、SIGIPIPE: 管道另一端沒(méi)有進(jìn)程接手?jǐn)?shù)據(jù)
9、EXC_BAD_INSTRUCTION:此類(lèi)異常通常由于線(xiàn)程執(zhí)行非法指令導(dǎo)致
10晾腔、EXC_ARITHMETIC:除零錯(cuò)誤會(huì)拋出此類(lèi)異常