了解和分析應(yīng)用程序崩潰報(bào)告
當(dāng)應(yīng)用程序崩潰時(shí),將創(chuàng)建崩潰報(bào)告,這對(duì)于理解導(dǎo)致崩潰的原因非常有用。本文檔包含有關(guān)如何符號(hào)化,理解和解釋崩潰報(bào)告的基本信息。
介紹
當(dāng)應(yīng)用程序崩潰時(shí),將創(chuàng)建崩潰報(bào)告并將其存儲(chǔ)在設(shè)備上。崩潰報(bào)告描述了應(yīng)用程序終止的條件,在大多數(shù)情況下,這些條件包括每個(gè)執(zhí)行線程的完整回溯,通常對(duì)于調(diào)試應(yīng)用程序中的問(wèn)題非常有用。您應(yīng)該查看這些崩潰報(bào)告,以了解應(yīng)用程序崩潰的原因,然后嘗試修復(fù)它們。
帶有回溯的崩潰報(bào)告需要先進(jìn)行符號(hào)化才能進(jìn)行分析。符號(hào)化將存儲(chǔ)器地址替換為易于理解的函數(shù)名稱(chēng)和行號(hào)。如果您通過(guò)Xcode的“設(shè)備”窗口從設(shè)備上注銷(xiāo)崩潰日志,那么幾秒鐘后它們將自動(dòng)為您表示。否則,您需要.crash通過(guò)將其導(dǎo)入Xcode Devices窗口來(lái)自己對(duì)文件進(jìn)行符號(hào)化。有關(guān)詳細(xì)信息,請(qǐng)參見(jiàn)符號(hào)化崩潰報(bào)告。
一個(gè)低內(nèi)存報(bào)告從其他的崩潰報(bào)告不同之處在于有這類(lèi)型的報(bào)告沒(méi)有回溯。當(dāng)發(fā)生內(nèi)存不足崩潰時(shí),您必須調(diào)查內(nèi)存使用模式以及對(duì)內(nèi)存不足警告的響應(yīng)。本文檔為您指出了一些可能有用的內(nèi)存管理參考。
獲取崩潰和內(nèi)存不足報(bào)告
調(diào)試已部署的iOS應(yīng)用程序討論了如何直接從iOS設(shè)備檢索崩潰和內(nèi)存不足報(bào)告。
《?App Distribution Guide?》中的“分析崩潰報(bào)告”討論了如何查看從TestFlight beta測(cè)試人員和從App Store下載了您的應(yīng)用程序的用戶(hù)收集的匯總崩潰報(bào)告。
象征崩潰報(bào)告
符號(hào)化是將回溯地址解析為源代碼方法或函數(shù)名稱(chēng)(稱(chēng)為符號(hào))的過(guò)程。如果不首先表示崩潰報(bào)告,則很難確定崩潰發(fā)生的位置。
注意:“?低內(nèi)存報(bào)告”不需要符號(hào)化。
注意:?macOS的崩潰報(bào)告在生成時(shí)通常被符號(hào)化或部分符號(hào)化。本節(jié)著重于用符號(hào)表示來(lái)自iOS,watchOS和tvOS的崩潰報(bào)告,但是對(duì)于macOS來(lái)說(shuō),整個(gè)過(guò)程是相似的。
圖1?崩潰報(bào)告和符號(hào)化過(guò)程概述。
當(dāng)編譯器將您的源代碼轉(zhuǎn)換成機(jī)器代碼時(shí),它還會(huì)生成調(diào)試符號(hào),這些調(diào)試符號(hào)將已編譯二進(jìn)制文件中的每條機(jī)器指令映射回其源代碼行。根據(jù)調(diào)試信息格式(DEBUG_INFORMATION_FORMAT)的構(gòu)建設(shè)置,這些調(diào)試符號(hào)將存儲(chǔ)在二進(jìn)制文件中或隨附的調(diào)試符號(hào)(dSYM)文件中。默認(rèn)情況下,應(yīng)用程序的調(diào)試版本將調(diào)試符號(hào)存儲(chǔ)在已編譯的二進(jìn)制文件中,而應(yīng)用程序的發(fā)布版本將調(diào)試符號(hào)存儲(chǔ)在配套dSYM文件中以減小二進(jìn)制文件的大小。
調(diào)試符號(hào)文件和應(yīng)用程序二進(jìn)制文件通過(guò)構(gòu)建UUID在每個(gè)構(gòu)建基礎(chǔ)上捆綁在一起。將為您的應(yīng)用程序的每個(gè)內(nèi)部版本生成一個(gè)新的UUID,并唯一標(biāo)識(shí)該內(nèi)部版本。即使使用相同的編譯器設(shè)置從相同的源代碼重建功能相同的可執(zhí)行文件,它也將具有不同的構(gòu)建UUID。來(lái)自后續(xù)版本的調(diào)試符號(hào)文件,即使來(lái)自相同的源文件,也不會(huì)與其他版本的二進(jìn)制文件互操作。
當(dāng)您存檔應(yīng)用程序以進(jìn)行分發(fā)時(shí),Xcode將與一起收集應(yīng)用程序二進(jìn)制文件。dSYM文件并將其存儲(chǔ)在主文件夾內(nèi)的某個(gè)位置。您可以在Xcode Organizer的“ Archived”部分下找到所有已存檔的應(yīng)用程序。有關(guān)創(chuàng)建檔案的更多信息,請(qǐng)參閱《App分發(fā)指南》。
重要提示:?要符號(hào)化測(cè)試人員,應(yīng)用程序?qū)彶楹涂蛻?hù)的崩潰報(bào)告,必須為分發(fā)的應(yīng)用程序的每個(gè)內(nèi)部版本保留存檔。
如果要通過(guò)App Store分發(fā)應(yīng)用程序,或使用Test Flight進(jìn)行Beta測(cè)試,則可以選擇dSYM在將存檔上傳到iTunes Connect時(shí)包括文件。在提交對(duì)話框中,選中“包括您的應(yīng)用程序的應(yīng)用程序符號(hào)...”。dSYM要接收從TestFlight用戶(hù)和選擇共享診斷數(shù)據(jù)的客戶(hù)收集的崩潰報(bào)告,必須上傳文件。有關(guān)崩潰報(bào)告服務(wù)的更多信息,請(qǐng)參閱《App分發(fā)指南》。
重要提示:?從應(yīng)用程序?qū)彶槭盏降谋罎?bào)告會(huì)unsymbolicated,即使你包括dSYM上傳您的檔案到iTunes Connect的情況下的文件。您將需要使用Xcode象征從App Review收到的任何崩潰報(bào)告。請(qǐng)參閱使用Xcode象征iOS崩潰報(bào)告。
當(dāng)您的應(yīng)用程序崩潰時(shí),會(huì)創(chuàng)建一個(gè)非符號(hào)化的崩潰報(bào)告并將其存儲(chǔ)在設(shè)備上。
用戶(hù)可以按照Debugging Deployed iOS Apps中的步驟直接從其設(shè)備檢索崩潰報(bào)告。如果您已經(jīng)通過(guò)AdHoc或Enterprise發(fā)行版分發(fā)了應(yīng)用程序,則這是從用戶(hù)那里獲取崩潰報(bào)告的唯一方法。
從設(shè)備中檢索到的崩潰報(bào)告沒(méi)有符號(hào)化,需要使用Xcode進(jìn)行符號(hào)化。Xcode使用dSYM與您的應(yīng)用程序二進(jìn)制文件關(guān)聯(lián)的文件,將回溯中的每個(gè)地址替換為其源代碼中的原始位置。結(jié)果是一個(gè)符號(hào)化的崩潰報(bào)告。
如果用戶(hù)選擇與Apple共享診斷數(shù)據(jù),或者用戶(hù)已通過(guò)TestFlight安裝了應(yīng)用程序的Beta版,則崩潰報(bào)告將上傳到App Store。
App Store象征著崩潰報(bào)告,并將其與類(lèi)似的崩潰報(bào)告進(jìn)行分組。這種相似的崩潰報(bào)告的匯總稱(chēng)為崩潰點(diǎn)。
在Xcode的崩潰管理器中可以使用帶符號(hào)的崩潰報(bào)告。
位碼
位碼是已編譯程序的中間表示。當(dāng)您存檔啟用了位碼的應(yīng)用程序時(shí),編譯器會(huì)生成包含位碼而不是機(jī)器碼的二進(jìn)制文件。二進(jìn)制文件上傳到App Store后,該位代碼將被編譯為機(jī)器代碼。App Store將來(lái)可能會(huì)再次編譯位代碼,以利用將來(lái)對(duì)編譯器的改進(jìn),而無(wú)需您采取任何措施。
圖2位?代碼編譯過(guò)程概述。
由于二進(jìn)制文件的最終編譯是在App Store上進(jìn)行的,因此您的Mac將不包含符號(hào)化dSYM從App Review或從其設(shè)備發(fā)送了崩潰報(bào)告的用戶(hù)收到的崩潰報(bào)告所需的調(diào)試符號(hào)()文件。盡管dSYM在歸檔應(yīng)用程序時(shí)會(huì)生成一個(gè)文件,但該文件是用于二進(jìn)制代碼的,不能用于表示崩潰報(bào)告。App Store可以dSYM從Xcode或iTunes Connect網(wǎng)站上下載位碼編譯過(guò)程中生成的文件。您必須下載這些dSYM文件,以表示從App Review或從其設(shè)備向您發(fā)送崩潰報(bào)告的用戶(hù)收到的崩潰報(bào)告。通過(guò)崩潰報(bào)告服務(wù)收到的崩潰報(bào)告將自動(dòng)被符號(hào)化。
重要提示:?由App Store編譯的二進(jìn)制文件將具有與最初提交的二進(jìn)制文件不同的UUID。
從Xcode下載dSYM文件
在檔案組織者中,選擇最初提交給App Store的檔案。
單擊下載dSYMs按鈕。
Xcode下載dSYM文件并將其插入到選定的檔案中。
從iTunes Connect網(wǎng)站下載dSYM文件
打開(kāi)“應(yīng)用程序詳細(xì)信息”頁(yè)面。
單擊活動(dòng)。
從“所有版本”列表中,選擇一個(gè)版本。
單擊下載dSYM鏈接。
將“隱藏”符號(hào)名稱(chēng)轉(zhuǎn)換回其原始名稱(chēng)
將帶有位碼的應(yīng)用程序上載到App Store時(shí),可以通過(guò)取消選中“提交”對(duì)話框中的“上載應(yīng)用程序的符號(hào)以從Apple接收符號(hào)報(bào)告”來(lái)選擇不發(fā)送應(yīng)用程序的符號(hào)。如果您選擇不將應(yīng)用程序的符號(hào)信息發(fā)送給Apple,則Xcode將替換應(yīng)用程序中的符號(hào)。dSYM將應(yīng)用程序發(fā)送到iTunes Connect之前,請(qǐng)使用帶有混淆符號(hào)(例如“ __hidden#109_”)的文件。Xcode在原始符號(hào)和“隱藏”符號(hào)之間創(chuàng)建映射,并將此映射存儲(chǔ).bcsymbolmap在應(yīng)用程序歸檔文件內(nèi)的文件中。每個(gè)。dSYM文件將有一個(gè)對(duì)應(yīng)的.bcsymbolmap文件。
在符號(hào)化崩潰報(bào)告之前,您需要對(duì)上的符號(hào)進(jìn)行模糊處理。dSYM從iTunes Connect下載的文件。如果您使用Xcode中的“下載dSYMs”按鈕,則將自動(dòng)為您執(zhí)行這種模糊處理。但是,如果您使用iTunes Connect網(wǎng)站下載。dSYM文件,打開(kāi)終端并使用以下命令對(duì)符號(hào)進(jìn)行模糊處理(將示例路徑替換為您自己的存檔和從iTunes Connect下載的dSYMs文件夾):
xcrun dsymutil -symbol-map?/ Library / Developer / Xcode / Archives / 2017-11-23 / MyGreatApp \ 11-23-17 \,\ 12.00 \ PM.xcarchive / BCSymbolMaps?/ Downloads / dSYMs / 3B15C133-88AA-35B0 -B8BA-84AF76826CE0.dSYM
對(duì)每個(gè)運(yùn)行此命令。dSYM您下載的dSYMs文件夾中的文件。
確定故障報(bào)告是否帶有符號(hào)
崩潰報(bào)告可能沒(méi)有符號(hào)化,完全符號(hào)化或部分符號(hào)化。未符號(hào)化的崩潰報(bào)告將在backtrace中不包含方法或函數(shù)名稱(chēng)。而是在加載的二進(jìn)制映像中具有可執(zhí)行代碼的十六進(jìn)制地址。在完全符號(hào)化的崩潰報(bào)告中,回溯的每一行中的十六進(jìn)制地址將替換為相應(yīng)的符號(hào)。在部分符號(hào)化的崩潰報(bào)告中,僅回溯中的某些地址已被其相應(yīng)的符號(hào)替換。
顯然,您應(yīng)該嘗試完全符號(hào)化您收到的任何崩潰報(bào)告,因?yàn)樗鼘⑻峁┯嘘P(guān)崩潰的最深刻見(jiàn)解。部分符號(hào)化的崩潰報(bào)告可能包含足夠的信息來(lái)理解崩潰,這取決于崩潰的類(lèi)型以及回溯的哪些部分已被成功符號(hào)化。非符號(hào)化的崩潰報(bào)告很少有用。
圖3?在不同符號(hào)級(jí)別的相同回溯。
使用Xcode象征iOS崩潰報(bào)告
Xcode將自動(dòng)嘗試用符號(hào)表示它遇到的所有崩潰報(bào)告。您只需要做的就是將崩潰報(bào)告添加到Xcode Organizer。
注意:?如果沒(méi)有.crash擴(kuò)展名,Xcode將不接受崩潰報(bào)告。如果您收到的崩潰報(bào)告中沒(méi)有擴(kuò)展名或具有.txt擴(kuò)展名,請(qǐng).crash按照以下步驟將其重命名為具有擴(kuò)展名。
將iOS設(shè)備連接到Mac
從“窗口”菜單中選擇“設(shè)備”
在左列的“設(shè)備”部分下,選擇一個(gè)設(shè)備
單擊右側(cè)面板“設(shè)備信息”部分下的“查看設(shè)備日志”按鈕
將您的崩潰報(bào)告拖到顯示面板的左列
Xcode將自動(dòng)符號(hào)化崩潰報(bào)告并顯示結(jié)果
為了表示崩潰報(bào)告,Xcode需要能夠找到以下內(nèi)容:
崩潰的應(yīng)用程序的二進(jìn)制dSYM文件和文件。
dSYM應(yīng)用程序鏈接到的所有自定義框架的二進(jìn)制文件和文件。對(duì)于使用應(yīng)用程序從源構(gòu)建的框架,其dSYM文件將與應(yīng)用程序的dSYM文件一起復(fù)制到存檔中。對(duì)于由第三方構(gòu)建的框架,您將需要向作者索要dSYM文件。
崩潰時(shí)正在運(yùn)行該應(yīng)用程序的操作系統(tǒng)的符號(hào)。這些符號(hào)包含特定OS版本(例如iOS 9.3.3)中包含的框架的調(diào)試信息。操作系統(tǒng)符號(hào)是特定于體系結(jié)構(gòu)的-適用于64位設(shè)備的iOS版本不會(huì)包含armv7符號(hào)。Xcode將自動(dòng)從您連接到Mac的每個(gè)設(shè)備中復(fù)制OS符號(hào)。
如果缺少這些,則Xcode可能無(wú)法符號(hào)化崩潰報(bào)告,或者只能部分符號(hào)化崩潰報(bào)告。
使用atos象征崩潰報(bào)告
的?阿托斯命令將數(shù)字地址轉(zhuǎn)換為其符號(hào)等效項(xiàng)。如果完整的調(diào)試符號(hào)信息可用,則輸出atos將包括文件名和源行號(hào)信息。該atos命令可用于符號(hào)化未符號(hào)化或部分符號(hào)化的崩潰報(bào)告的回溯中的各個(gè)地址。使用atos以下符號(hào)表示崩潰報(bào)告的一部分:
在回溯中找到要符號(hào)化的線。在第二列中注意二進(jìn)制映像的名稱(chēng),在第三列中注意地址。
在崩潰報(bào)告底部的二進(jìn)制圖像列表中查找具有該名稱(chēng)的二進(jìn)制圖像。注意二進(jìn)制映像的體系結(jié)構(gòu)和加載地址。
圖4?崩潰報(bào)告中需要使用的信息atos。
找到dSYM二進(jìn)制文件。您可以使用Spotlight查找dSYM二進(jìn)制圖像的UUID?的匹配文件。請(qǐng)參閱“?符號(hào)故障排除”部分。dSYM文件是捆綁軟件,其中包含一個(gè)文件,其中包含編譯器在構(gòu)建時(shí)生成的DWARF調(diào)試信息。dSYM調(diào)用時(shí),必須提供此文件的路徑,而不是束的路徑atos。
通過(guò)以上信息,您可以使用atos命令在回溯中用符號(hào)表示地址。您可以指定多個(gè)符號(hào)地址,以空格分隔。
atos -arch <Binary Architecture> -o <Path to dSYM file>/Contents/Resources/DWARF/<binary image name> -l <load address> <address to symbolicate>
清單1atos遵循上述步驟??的命令用法示例以及結(jié)果輸出。
$ atos -arch arm64 -o TheElements.app.dSYM / Contents / Resources / DWARF / TheElements -l 0x1000e4000 0x00000001000effdc
-[AtomicElementViewController myTransitionDidStop:完成:上下文:]
符號(hào)故障排除
如果Xcode無(wú)法完全表示崩潰報(bào)告,則可能是因?yàn)镸ac缺少dSYM應(yīng)用程序二進(jìn)制dSYM文件,應(yīng)用程序鏈接到的一個(gè)或多個(gè)框架的文件,或應(yīng)用程序運(yùn)行時(shí)所用操作系統(tǒng)的設(shè)備符號(hào)它崩潰了。以下步驟顯示了如何使用Spotlight確定dSYM在二進(jìn)制映像中是否需要用符號(hào)表示回溯地址的文件。
圖5?找到二進(jìn)制圖像的UUID。
在回溯中找到Xcode無(wú)法符號(hào)化的行。在第二列中注意二進(jìn)制映像的名稱(chēng)。
在崩潰報(bào)告底部的二進(jìn)制圖像列表中查找具有該名稱(chēng)的二進(jìn)制圖像。該列表包含崩潰時(shí)加載到進(jìn)程中的每個(gè)二進(jìn)制映像的UUID。
清單2?您可以使用grep命令行工具在二進(jìn)制圖像列表中快速找到條目。
$ grep --after-context = 1000“二進(jìn)制圖像:” <崩潰報(bào)告的路徑> | grep <二進(jìn)制名稱(chēng)>
將二進(jìn)制圖像的UUID轉(zhuǎn)換為以8-4-4-4-12(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)組分隔的32個(gè)字符串。請(qǐng)注意,所有字母都必須大寫(xiě)。
mdfind使用查詢(xún)使用命令行工具搜索UUID?"com_apple_xcode_dsym_uuids == <UUID>"(包括引號(hào))。
清單3?使用mdfind命令行工具搜索dSYM具有給定UUID的文件。
$ mdfind“ com_apple_xcode_dsym_uuids == <UUID>”
如果Spotlight找到dSYM用于UUID?的文件,mdfind則將打印該dSYM文件的路徑以及可能包含其存檔的路徑。如果dSYM找不到用于UUID?的文件,?mdfind將退出而不打印任何內(nèi)容。
如果Spotlight找到了dSYM二進(jìn)制文件,但是Xcode無(wú)法在該二進(jìn)制映像中符號(hào)化地址,那么您應(yīng)該提交錯(cuò)誤。將崩潰報(bào)告和相關(guān)dSYM文件附加到錯(cuò)誤報(bào)告。解決方法是,您可以使用手動(dòng)標(biāo)記地址atos。請(qǐng)參閱使用atos象征崩潰報(bào)告。
如果Spotlight找不到dSYM二進(jìn)制映像的,請(qǐng)確認(rèn)您仍然具有崩潰的應(yīng)用程序版本的Xcode歸檔文件,并且該歸檔文件位于Spotlight可以找到它的某個(gè)位置(主目錄中的任何位置都可以)。如果您的應(yīng)用程序是在啟用了位碼的情況下構(gòu)建的,請(qǐng)確保dSYM已從App Store?下載了用于最終編譯的文件。請(qǐng)參閱從Xcode下載dSYM文件。
如果您認(rèn)為dSYM二進(jìn)制映像是正確的,則可以使用dwarfdump命令來(lái)打印匹配的UUID。您也可以使用該dwarfdump命令來(lái)打印二進(jìn)制文件的UUID。
xcrun dwarfdump --uuid <Path to dSYM file>
注意:?您必須擁有最初提交給App Store的崩潰應(yīng)用程序版本的存檔。的dSYM文件和應(yīng)用程序二進(jìn)制每個(gè)累積的基礎(chǔ)上具體綁在一起。即使使用相同的來(lái)源和構(gòu)建配置來(lái)創(chuàng)建新的存檔,也不會(huì)生成dSYM可以與崩潰的構(gòu)建進(jìn)行互操作的文件。
如果您不再擁有此存檔,則應(yīng)提交保留該存檔的應(yīng)用程序的新版本。然后,您將可以使用符號(hào)表示此新版本的崩潰報(bào)告。
分析崩潰報(bào)告
本部分討論在標(biāo)準(zhǔn)崩潰報(bào)告中找到的每個(gè)部分。
標(biāo)頭
每個(gè)崩潰報(bào)告都以標(biāo)題開(kāi)頭。
清單4?崩潰報(bào)告中標(biāo)頭的節(jié)選。
事件標(biāo)識(shí)符:B6FD1E8E-B39F-430B-ADDE-FC3A45ED368C
CrashReporter密鑰:f04e68ec62d3c66057628c9ba9839e30d55937dc
硬件型號(hào):iPad6,8
工藝:TheElements [303]
路徑:/private/var/containers/Bundle/Application/888C1FA2-3666-4AE2-9E8E-62E2F787DEC1/TheElements.app/TheElements
標(biāo)識(shí)符:com.example.apple-samplecode.TheElements
版本:1.12
代碼類(lèi)型:ARM-64(本機(jī))
角色:前臺(tái)
父流程:已啟動(dòng)[1]
聯(lián)盟:com.example.apple-samplecode.TheElements [402]
日期/時(shí)間:2016-08-22 10:43:07.5806 -0700
發(fā)布時(shí)間:2016-08-22 10:43:01.0293 -0700
作業(yè)系統(tǒng)版本:iPhone OS 10.0(14A5345a)
報(bào)告版本:104
大多數(shù)字段是不言自明的,但有些字段值得特別注意:
事件標(biāo)識(shí)符:報(bào)告的唯一標(biāo)識(shí)符。兩個(gè)報(bào)告永遠(yuǎn)不會(huì)共享相同的事件標(biāo)識(shí)符。
CrashReporter密鑰:每個(gè)設(shè)備的匿名標(biāo)識(shí)符。來(lái)自同一設(shè)備的兩個(gè)報(bào)告將包含相同的值。
Beta標(biāo)識(shí)符:崩潰的應(yīng)用程序的設(shè)備和供應(yīng)商的組合的唯一標(biāo)識(shí)符。來(lái)自同一供應(yīng)商和同一設(shè)備的兩個(gè)應(yīng)用程序報(bào)告將包含相同的值。該字段僅出現(xiàn)在為通過(guò)TestFlight分發(fā)的應(yīng)用程序生成的崩潰報(bào)告中,并替換了CrashReporter Key字段。
進(jìn)程:崩潰的進(jìn)程的可執(zhí)行文件名。這與CFBundleExecutable應(yīng)用程序的信息屬性列表中鍵的值匹配。
版本:崩潰的進(jìn)程的版本。該字段的值是崩潰的應(yīng)用程序的CFBundleVersion和的串聯(lián)CFBundleVersionString。
代碼類(lèi)型:崩潰的進(jìn)程的目標(biāo)體系結(jié)構(gòu)。這將是一ARM-64,ARM,x86-64,或x86。
作用:終止時(shí)分配給進(jìn)程的task_role。
操作系統(tǒng)版本:發(fā)生崩潰的操作系統(tǒng)版本,包括內(nèi)部版本號(hào)。
異常信息
不要與Objective-C / C ++異常混淆(盡管其中一種可能是崩潰的原因),本節(jié)列出了Mach?異常類(lèi)型和相關(guān)字段,它們提供了有關(guān)崩潰性質(zhì)的信息。并非所有字段都會(huì)出現(xiàn)在每個(gè)崩潰報(bào)告中。
清單5?摘自Exception Codes部分的摘錄,該崩潰報(bào)告是由于未捕獲的Objective-C異常而導(dǎo)致進(jìn)程終止時(shí)生成的崩潰報(bào)告。
異常類(lèi)型:EXC_CRASH(SIGABRT)
異常代碼:0x0000000000000000、0x0000000000000000
異常說(shuō)明:EXC_CORPSE_NOTIFY
線程觸發(fā):0
清單6?摘自流程終止報(bào)告,該報(bào)表是由于進(jìn)程取消引用NULL指針而導(dǎo)致的崩潰報(bào)告。
異常類(lèi)型:EXC_BAD_ACCESS(SIGSEGV)
異常子類(lèi)型:KERN_INVALID_ADDRESS位于0x0000000000000000
終止信號(hào):分段故障:11
終止原因:命名空間SIGNAL,代碼0xb
終止過(guò)程:排除處理程序[0]
線程觸發(fā):0
下面介紹了此部分中可能出現(xiàn)的字段。
異常代碼:處理器特定的有關(guān)異常的信息,編碼為一個(gè)或多個(gè)64位十六進(jìn)制數(shù)字。通常,此字段將不存在,因?yàn)镃rash Reporter解析異常代碼以將其作為其他字段中的人類(lèi)可讀描述來(lái)呈現(xiàn)。
異常子類(lèi)型:異常代碼的人類(lèi)可讀名稱(chēng)。
異常消息:從異常代碼中提取的其他人類(lèi)可讀信息。
異常說(shuō)明:并非特定于一種異常類(lèi)型的其他信息。如果包含該字段,SIMULATED (this is NOT a crash)則該進(jìn)程不會(huì)崩潰,但應(yīng)系統(tǒng)(通常是看門(mén)狗)的請(qǐng)求而終止。
終止原因:進(jìn)程終止時(shí)指定的退出原因信息。進(jìn)程內(nèi)部和外部的關(guān)鍵系統(tǒng)組件都會(huì)在遇到致命錯(cuò)誤(例如,錯(cuò)誤的代碼簽名,缺少的依賴(lài)庫(kù)或沒(méi)有適當(dāng)權(quán)利的情況下訪問(wèn)隱私敏感信息)時(shí)終止進(jìn)程。macOS Sierra,iOS 10,watchOS 3和tvOS 10已采用新的基礎(chǔ)結(jié)構(gòu)來(lái)記錄這些錯(cuò)誤,并且由這些操作系統(tǒng)生成的崩潰報(bào)告在“終止原因”字段中列出了錯(cuò)誤消息。
由Thread觸發(fā):引發(fā)異常的線程。
以下各節(jié)介紹了一些最常見(jiàn)的異常類(lèi)型:
錯(cuò)誤的內(nèi)存訪問(wèn)[EXC_BAD_ACCESS // SIGSEGV // SIGBUS]
該進(jìn)程嘗試訪問(wèn)無(wú)效的內(nèi)存,或者嘗試以?xún)?nèi)存保護(hù)級(jí)別不允許的方式訪問(wèn)內(nèi)存(例如,寫(xiě)入只讀內(nèi)存)。“?異常子類(lèi)型”字段包含kern_return_t描述錯(cuò)誤和被錯(cuò)誤訪問(wèn)的內(nèi)存地址。
以下是一些調(diào)試錯(cuò)誤的內(nèi)存訪問(wèn)崩潰的提示:
如果objc_msgSend或在崩潰線程objc_release的Backtrace頂部附近,則該進(jìn)程可能已嘗試向已釋放對(duì)象發(fā)送消息。您應(yīng)該使用Zombies儀器來(lái)分析應(yīng)用程序,以更好地了解此崩潰的情況。
如果在崩潰線程gpus_ReturnNotPermittedKillClient的Backtraces頂部附近,則該進(jìn)程被終止,因?yàn)樵撨M(jìn)程試圖在后臺(tái)使用OpenGL ES或Metal進(jìn)行渲染。請(qǐng)參閱QA1766:移至后臺(tái)時(shí)如何修復(fù)OpenGL ES應(yīng)用程序崩潰。
在啟用了地址清理程序的情況下運(yùn)行您的應(yīng)用程序。地址清理器在編譯后的代碼中為內(nèi)存訪問(wèn)添加了其他工具。當(dāng)您的應(yīng)用程序運(yùn)行時(shí),Xcode會(huì)警告您是否以可能導(dǎo)致崩潰的方式訪問(wèn)內(nèi)存。
異常退出[EXC_CRASH // SIGABRT]
該過(guò)程異常退出。這種異常類(lèi)型導(dǎo)致崩潰的最常見(jiàn)原因是未捕獲的Objective-C / C ++?異常和對(duì)的調(diào)用abort()。
如果擴(kuò)展程序花費(fèi)太多時(shí)間進(jìn)行初始化(監(jiān)視程序終止),則該擴(kuò)展程序?qū)⒁赃@種異常類(lèi)型終止。如果某個(gè)擴(kuò)展由于啟動(dòng)時(shí)掛起而被殺死,則生成的崩潰報(bào)告的Exception Subtype將為L(zhǎng)AUNCH_HANG。因?yàn)閿U(kuò)展沒(méi)有main功能,所以花在初始化上的任何時(shí)間都會(huì)在+load擴(kuò)展和從屬庫(kù)中的靜態(tài)構(gòu)造函數(shù)和方法中發(fā)生。您應(yīng)該盡可能多地推遲這項(xiàng)工作。
跟蹤陷阱[EXC_BREAKPOINT // SIGTRAP]
與異常退出類(lèi)似,此異常旨在使附加的調(diào)試器有機(jī)會(huì)在執(zhí)行的特定點(diǎn)中斷進(jìn)程。您可以使用該__builtin_trap()函數(shù)從自己的代碼中觸發(fā)此異常。如果未連接調(diào)試器,則過(guò)程終止,并生成崩潰報(bào)告。
遇到致命錯(cuò)誤時(shí),較低級(jí)的庫(kù)(例如libdispatch)將捕獲該進(jìn)程。可以在崩潰報(bào)告的“?其他診斷信息”部分或設(shè)備的控制臺(tái)中找到有關(guān)該錯(cuò)誤的其他信息。
如果在運(yùn)行時(shí)遇到意外情況,則Swift代碼將以此異常類(lèi)型終止,例如:
值為nil的非可選類(lèi)型
強(qiáng)制類(lèi)型轉(zhuǎn)換失敗
查看回溯以確定在哪里遇到意外情況。其他信息也可能已記錄到設(shè)備的控制臺(tái)中。您應(yīng)該在崩潰位置修改代碼以妥善處理運(yùn)行時(shí)故障。例如,使用“?可選綁定”而不是強(qiáng)制展開(kāi)可選對(duì)象。
非法指令[EXC_BAD_INSTRUCTION // SIGILL]
進(jìn)程試圖執(zhí)行非法或未定義的指令。該過(guò)程可能試圖通過(guò)配置錯(cuò)誤的函數(shù)指針跳到無(wú)效地址。
在Intel處理器上,ud2操作碼會(huì)導(dǎo)致EXC_BAD_INSTRUCTION異常,但通常用于捕獲進(jìn)程以進(jìn)行調(diào)試。如果在運(yùn)行時(shí)遇到意外情況,則英特爾處理器上的Swift代碼將以此異常類(lèi)型終止。有關(guān)詳細(xì)信息,請(qǐng)參見(jiàn)跟蹤陷阱。
退出[SIGQUIT]
該進(jìn)程是在另一個(gè)具有管理其生存期權(quán)限的進(jìn)程的請(qǐng)求下終止的。SIGQUIT這并不意味著該過(guò)程已崩潰,但是它確實(shí)有可能以可檢測(cè)的方式發(fā)生錯(cuò)誤。
在iOS上,如果加載時(shí)間太長(zhǎng),主機(jī)應(yīng)用將退出鍵盤(pán)擴(kuò)展。崩潰報(bào)告中顯示的Backtrace不太可能指向負(fù)責(zé)的代碼。最有可能的是,擴(kuò)展的啟動(dòng)路徑上的其他一些代碼花了很長(zhǎng)時(shí)間才能完成,但在時(shí)間限制之前完成了,并且在退出擴(kuò)展時(shí),執(zhí)行移至了Backtraces中顯示的代碼上。您應(yīng)該對(duì)擴(kuò)展進(jìn)行概要分析,以更好地了解啟動(dòng)期間大部分工作的發(fā)生位置,并將該工作移至后臺(tái)線程或?qū)⑵渫七t到以后(加載擴(kuò)展后)。
被殺[SIGKILL]
該過(guò)程應(yīng)系統(tǒng)的要求終止。查看終止原因字段,以更好地了解終止原因。
該終止原因字段將包含一個(gè)名稱(chēng)空間,然后一個(gè)代碼。以下代碼特定于watchOS:
終止代碼0xc51bad01表示監(jiān)視應(yīng)用程序已終止,因?yàn)樗趫?zhí)行后臺(tái)任務(wù)時(shí)占用了過(guò)多的CPU時(shí)間。要解決此問(wèn)題,請(qǐng)優(yōu)化執(zhí)行后臺(tái)任務(wù)的代碼以提高CPU效率,或者減少應(yīng)用程序在后臺(tái)運(yùn)行時(shí)執(zhí)行的工作量。
終止代碼0xc51bad02表示監(jiān)視應(yīng)用程序已終止,因?yàn)樗茨茉诜峙涞臅r(shí)間內(nèi)完成后臺(tái)任務(wù)。要解決此問(wèn)題,請(qǐng)減少應(yīng)用程序在后臺(tái)運(yùn)行時(shí)執(zhí)行的工作量。
終止代碼0xc51bad03指示監(jiān)視應(yīng)用程序未能在分配的時(shí)間內(nèi)完成后臺(tái)任務(wù),并且系統(tǒng)總體上十分繁忙,以至于該應(yīng)用程序可能沒(méi)有收到太多的CPU時(shí)間來(lái)執(zhí)行后臺(tái)任務(wù)。盡管應(yīng)用程序可以通過(guò)減少在后臺(tái)任務(wù)中執(zhí)行的工作量來(lái)避免該問(wèn)題,0xc51bad03但并不表示該應(yīng)用程序做錯(cuò)了什么。該應(yīng)用更有可能由于整體系統(tǒng)負(fù)載而無(wú)法完成其工作。
受保護(hù)的資源違規(guī)[EXC_GUARD]
該過(guò)程違反了受保護(hù)的資源保護(hù)。系統(tǒng)庫(kù)可能會(huì)將某些文件描述符標(biāo)記為受保護(hù)的,然后對(duì)這些描述符的正常操作將觸發(fā)EXC_GUARD異常(當(dāng)要對(duì)這些文件描述符進(jìn)行操作時(shí),系統(tǒng)將使用特殊的“受保護(hù)”專(zhuān)用API)。這可以幫助您快速查找問(wèn)題,例如關(guān)閉由系統(tǒng)庫(kù)打開(kāi)的文件描述符。例如,如果某個(gè)應(yīng)用程序關(guān)閉了用于訪問(wèn)支持Core Data存儲(chǔ)的SQLite文件的文件描述符,則Core Data隨后會(huì)神秘地崩潰。保護(hù)異常使這些問(wèn)題能更快地被發(fā)現(xiàn),從而使它們更易于調(diào)試。
來(lái)自較新版本的iOS的崩潰報(bào)告EXC_GUARD在“?異常子類(lèi)型”和“?異常消息”字段中包含有關(guān)導(dǎo)致異常的操作的易于理解的詳細(xì)信息。在來(lái)自macOS或更舊版本的iOS的崩潰報(bào)告中,此信息被編碼為第一個(gè)“?異常代碼”作為位字段,其分解如下:
[63:61]-保護(hù)類(lèi)型:受保護(hù)資源的類(lèi)型。值0x2表示資源是文件描述符。
[60:32]-風(fēng)味:觸發(fā)??違規(guī)的條件。
如果(1 << 0)設(shè)置了第一位,則進(jìn)程嘗試close()在受保護(hù)的文件描述符上調(diào)用。
如果第二(1 << 1)位設(shè)置,過(guò)程試圖調(diào)用dup(),dup2()或fcntl()用F_DUPFD或F_DUPFD_CLOEXEC命令在把守的文件描述符。
如果(1 << 2)設(shè)置了第三位,則進(jìn)程嘗試通過(guò)套接字發(fā)送受保護(hù)的文件描述符。
如果(1 << 4)設(shè)置了第五位,則進(jìn)程嘗試寫(xiě)入受保護(hù)的文件描述符。
[31:0]-文件描述符:進(jìn)程嘗試修改的受保護(hù)文件描述符。
資源限制[EXC_RESOURCE]
該過(guò)程超出了資源消耗限制。這是來(lái)自操作系統(tǒng)的通知,通知該進(jìn)程正在使用太多資源。確切的資源列在“?異常子類(lèi)型”字段中。如果Exception Note字段包含NON-FATAL CONDITION,則即使生成了崩潰報(bào)告,該進(jìn)程也沒(méi)有被殺死。
異常子類(lèi)型MEMORY表示進(jìn)程已超過(guò)系統(tǒng)施加的內(nèi)存限制。這可能是終止使用過(guò)多內(nèi)存的先決條件。
異常子類(lèi)型WAKEUPS表示該進(jìn)程中的線程每秒被喚醒太多次,這迫使CPU非常頻繁地喚醒并消耗電池壽命。
通常,這是由線程間通信(通常使用peformSelector:onThread:或dispatch_async)引起的,這種通信不經(jīng)意地發(fā)生的次數(shù)比應(yīng)有的多。由于觸發(fā)此異常的通信種類(lèi)經(jīng)常發(fā)生,因此通常會(huì)有多個(gè)后臺(tái)線程具有非常相似的Backtraces(回溯)?-指示通信起源。
其他異常類(lèi)型
一些崩潰報(bào)告可能包含未命名的Exception Type,它將以十六進(jìn)制值(例如00000020)打印。如果您收到這些崩潰報(bào)告之一,請(qǐng)直接查看“?異常代碼”字段以了解更多信息。
異常代碼0xbaaaaaad表示該日志是整個(gè)系統(tǒng)的堆棧快照,而不是崩潰報(bào)告。要拍攝快照,請(qǐng)同時(shí)按側(cè)面按鈕和兩個(gè)音量按鈕。這些日志通常是用戶(hù)意外創(chuàng)建的,它們并不表示錯(cuò)誤。
異常代碼0xbad22222表示VoIP應(yīng)用程序已被iOS終止,因?yàn)樗謴?fù)得太頻繁了。
異常代碼0x8badf00d表示應(yīng)用程序已被iOS終止,因?yàn)榘l(fā)生了看門(mén)狗超時(shí)。該應(yīng)用程序啟動(dòng),終止或響應(yīng)系統(tǒng)事件花了太長(zhǎng)時(shí)間。一個(gè)常見(jiàn)的原因是在主線程上進(jìn)行同步網(wǎng)絡(luò)連接。無(wú)論執(zhí)行什么操作,都Thread 0需要將其移至后臺(tái)線程,或進(jìn)行不同的處理,以免阻塞主線程。
異常代碼0xc00010ff表示該應(yīng)用程序因響應(yīng)熱事件而被操作系統(tǒng)殺死。這可能是由于發(fā)生此崩潰的特定設(shè)備的問(wèn)題或其運(yùn)行的環(huán)境引起的。有關(guān)使您的應(yīng)用程序更有效運(yùn)行的提示,請(qǐng)參閱iOS的性能和Power Develops with Instruments?WWDC會(huì)話。
異常代碼0xdead10cc表示應(yīng)用程序已被操作系統(tǒng)終止,因?yàn)樵趻炱疬^(guò)程中該應(yīng)用程序保留了文件鎖或sqlite數(shù)據(jù)庫(kù)鎖。如果您的應(yīng)用程序在掛起時(shí)對(duì)鎖定的文件或sqlite數(shù)據(jù)庫(kù)執(zhí)行操作,則它必須請(qǐng)求額外的后臺(tái)執(zhí)行時(shí)間來(lái)完成這些操作,并在掛起之前放棄鎖定。
異常代碼0x2bad45ec表示應(yīng)用程序由于安全違規(guī)而已被iOS終止。終止描述“在安全模式下檢測(cè)到進(jìn)程在執(zhí)行不安全繪圖時(shí)”,表示該應(yīng)用嘗試在不允許的情況下(例如在屏幕鎖定時(shí))在屏幕上進(jìn)行繪制。用戶(hù)可能不會(huì)注意到此終止,因?yàn)榇私K止發(fā)生時(shí),屏幕關(guān)閉或顯示了鎖定屏幕。
注意:?使用應(yīng)用程序切換器終止已暫停的應(yīng)用程序不會(huì)生成崩潰報(bào)告。應(yīng)用暫停后,它隨時(shí)可以通過(guò)iOS終止,因此不會(huì)生成崩潰報(bào)告。
其他診斷信息
本節(jié)包括特定于終止類(lèi)型的其他診斷信息,其中可能包括:
特定于應(yīng)用程序的信息:在過(guò)程終止之前捕獲的框架錯(cuò)誤消息
內(nèi)核消息:有關(guān)代碼簽名問(wèn)題的詳細(xì)信息
Dyld錯(cuò)誤消息:動(dòng)態(tài)鏈接器發(fā)出的錯(cuò)誤消息
從macOS Sierra,iOS 10,watchOS 3和tvOS 10開(kāi)始,現(xiàn)在大多數(shù)信息在“?異常信息”下的“?終止原因”字段中報(bào)告。
您應(yīng)該閱讀本節(jié),以更好地了解終止過(guò)程的情況。
清單7?特定進(jìn)程部分的節(jié)選摘錄,該報(bào)告是由于找不到與之鏈接的框架而在終止進(jìn)程時(shí)生成的崩潰報(bào)告。
Dyld錯(cuò)誤消息:
Dyld消息:庫(kù)未加載:@ rpath / MyCustomFramework.framework / MyCustomFramework
? 引用自:/private/var/containers/Bundle/Application/CD9DB546-A449-41A4-A08B-87E57EE11354/TheElements.app/TheElements
? 原因:未找到合適的圖像。
清單8?摘自“特定于應(yīng)用程序的信息”部分的內(nèi)容,該文件是由于進(jìn)程未能快速加載其初始視圖控制器而終止時(shí)生成的崩潰報(bào)告。
特定于應(yīng)用程序的信息:
com.example.apple-samplecode.TheElements在19.81s之后無(wú)法場(chǎng)景創(chuàng)建(啟動(dòng)花費(fèi)了0.19s的總時(shí)長(zhǎng)20.00s)
已耗用的總CPU時(shí)間(秒):7.690(用戶(hù)7.690,系統(tǒng)0.000),19%CPU
應(yīng)用程序經(jīng)過(guò)的CPU時(shí)間(秒):0.697,2%CPU
回溯
崩潰報(bào)告中最有趣的部分是進(jìn)程終止時(shí)每個(gè)進(jìn)程線程的回溯。這些跟蹤中的每一個(gè)都與您在調(diào)試器中暫停過(guò)程時(shí)看到的類(lèi)似。
清單9?完全符號(hào)化的崩潰報(bào)告的Backtrace部分的節(jié)選。
線程0名稱(chēng):調(diào)度隊(duì)列:com.apple.main-thread
線程0崩潰:
0 TheElements 0x000000010006bc20-[AtomicElementViewController myTransitionDidStop:完成:上下文:](AtomicElementViewController.m:203)
1 UIKit 0x0000000194cef0f0-[UIViewAnimationState sendDelegateAnimationDidStop:完成:] + 312
2 UIKit 0x0000000194ceef30-[UIViewAnimationState animationDidStop:完成:] + 160
3 QuartzCore 0x0000000192178404 CA :: Layer :: run_animation_callbacks(void *)+ 260
4 libdispatch.dylib 0x000000018dd6d1c0 _dispatch_client_callout + 16
5 libdispatch.dylib 0x000000018dd71d6c _dispatch_main_queue_callback_4CF + 1000
6 CoreFoundation 0x000000018ee91f2c __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
7 CoreFoundation 0x000000018ee8fb18 __CFRunLoopRun + 1660
8 CoreFoundation 0x000000018edbe048 CFRunLoopRunSpecific + 444
9 GraphicsServices 0x000000019083f198 GSEventRunModal + 180
10 UIKit 0x0000000194d21bd0-[UIApplication _run] + 684
11 UIKit 0x0000000194d1c908 UIApplicationMain + 208
12 TheElements 0x00000001000653c0 main(main.m:55)
13 libdyld.dylib 0x000000018dda05b8開(kāi)始+ 4
線程1:
0 libsystem_kernel.dylib 0x000000018deb2a88 __workq_kernreturn + 8
1個(gè)libsystem_pthread.dylib 0x000000018df75188 _pthread_wqthread + 968
2 libsystem_pthread.dylib 0x000000018df74db4 start_wqthread + 4
...
第一行列出了線程號(hào)和當(dāng)前正在執(zhí)行的調(diào)度隊(duì)列的標(biāo)識(shí)符。其余各行列出了有關(guān)回溯中各個(gè)堆棧幀的詳細(xì)信息。從左到右:
堆棧幀號(hào)。堆棧幀按調(diào)用順序顯示,其中零幀是停止執(zhí)行時(shí)正在執(zhí)行的函數(shù)。第一幀是在零幀中調(diào)用該函數(shù)的函數(shù),依此類(lèi)推。
堆棧幀的執(zhí)行功能所在的二進(jìn)制文件的名稱(chēng)。
對(duì)于幀零,執(zhí)行暫停時(shí)正在執(zhí)行的機(jī)器指令的地址。對(duì)于其余的堆棧幀,當(dāng)控制權(quán)返回到堆棧幀時(shí),下一條將執(zhí)行的機(jī)器指令的地址。
在帶符號(hào)的崩潰報(bào)告中,函數(shù)在堆棧框架中的方法名稱(chēng)。
例外情況
Objective-C中的異常用于指示在運(yùn)行時(shí)檢測(cè)到的編程錯(cuò)誤,例如訪問(wèn)索引超出范圍的數(shù)組,嘗試對(duì)不可變對(duì)象進(jìn)行突變,未實(shí)現(xiàn)協(xié)議的必需方法或發(fā)送以下消息:接收器無(wú)法識(shí)別。
注意:?向先前釋放的對(duì)象發(fā)送消息可能會(huì)引發(fā),NSInvalidArgumentException而不是因內(nèi)存訪問(wèn)沖突而使程序崩潰。當(dāng)在先前由已釋放對(duì)象占用的內(nèi)存中分配新對(duì)象時(shí),會(huì)發(fā)生這種情況。如果您的應(yīng)用程序由于未捕獲而崩潰NSInvalidArgumentException(請(qǐng)-[NSObject(NSObject) doesNotRecognizeSelector:]在異常回溯中查找),請(qǐng)考慮使用Zombies工具對(duì)應(yīng)用程序進(jìn)行性能分析,以消除導(dǎo)致內(nèi)存管理不當(dāng)?shù)目赡苄浴?/p>
如果未捕獲到異常,則該異常將被稱(chēng)為未捕獲的異常處理程序的函數(shù)攔截。默認(rèn)的未捕獲異常處理程序?qū)惓O⒂涗浀皆O(shè)備的控制臺(tái),然后終止該過(guò)程。在Last Exception Backtrace部分下,只有異常backtrace被寫(xiě)入生成的崩潰報(bào)告,如清單10所示。崩潰消息中省略了異常消息。如果您收到帶有上次異常回溯的崩潰報(bào)告,則應(yīng)該從原始設(shè)備獲取控制臺(tái)日志,以更好地了解導(dǎo)致異常的情況。
清單10?未經(jīng)符號(hào)化的崩潰報(bào)告的Last Exception Backtrace部分的節(jié)選。
最后異常回溯:
(0x18eee41c0 0x18d91c55c 0x18eee3e88 0x18f8ea1a0 0x195013fe4 0x1951acf20 0x18ee03dc4 0x1951ab8f4 0x195458128 0x19545fa20 0x19545fc7c 0x19545ff70 0x194de4594 0x194e94e8c 0x194f47d8c 0x194f39b40 0x194ca92ac 0x18ee917dc 0x18ee8f40c 0x18ee8f89c 0x18edbe048 0x19083f198 0x194d21bd0 0x194d1c908 0x1000ad45c 0x18dda05b8)
帶有Last Exception Backtrace僅包含十六進(jìn)制地址的崩潰日志必須用符號(hào)表示,以產(chǎn)生可用的backtrace,如清單11所示。
清單11?帶有符號(hào)的崩潰報(bào)告中的Last Exception Backtrace部分的節(jié)選。在應(yīng)用的故事板上加載場(chǎng)景時(shí)引發(fā)了此異常。缺少與場(chǎng)景中某個(gè)元素的連接的相應(yīng)IBOutlet。
最后異常回溯:
0 CoreFoundation 0x18eee41c0 __exceptionPreprocess + 124
1個(gè)libobjc.A.dylib 0x18d91c55c objc_exception_throw + 56
2 CoreFoundation 0x18eee3e88-[NSException提高] + 12
3基礎(chǔ)0x18f8ea1a0-[NSObject(NSKeyValueCoding)setValue:forKey:] + 272
4 UIKit 0x195013fe4-[UIViewController setValue:forKey:] + 104
5 UIKit 0x1951acf20-[UIRuntimeOutletConnection連接] + 124
6 CoreFoundation 0x18ee03dc4-[NSArray makeObjectsPerformSelector:] + 232
7 UIKit 0x1951ab8f4-[UINib InstantiateWithOwner:options:] + 1756
8 UIKit 0x195458128-[UIStoryboard實(shí)例化ViewControllerWithIdentifier:] + 196
9 UIKit 0x19545fa20-[UIStoryboardSegueTemplate實(shí)例化OrFindDestinationViewControllerWithSender:] + 92
10 UIKit 0x19545fc7c-[UIStoryboardSegueTemplate _perform:] + 56
11 UIKit 0x19545ff70-[UIStoryboardSegueTemplate執(zhí)行:] + 160
12 UIKit 0x194de4594-[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1352
13 UIKit 0x194e94e8c-[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 268
14 UIKit 0x194f47d8c _runAfterCACommitDeferredBlocks + 292
15 UIKit 0x194f39b40 _cleanUpAfterCAFlushAndRunDeferredBlocks + 560
16 UIKit 0x194ca92ac _afterCACommitHandler + 168
17 CoreFoundation 0x18ee917dc __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32
18 CoreFoundation 0x18ee8f40c __CFRunLoopDoObservers + 372
19 CoreFoundation 0x18ee8f89c __CFRunLoopRun + 1024
20 CoreFoundation 0x18edbe048 CFRunLoopRunSpecific + 444
21 GraphicsServices 0x19083f198 GSEventRunModal + 180
22 UIKit 0x194d21bd0-[UIApplication _run] + 684
23 UIKit 0x194d1c908 UIApplicationMain + 208
24 TheElements 0x1000ad45c main(main.m:55)
25 libdyld.dylib 0x18dda05b8開(kāi)始+ 4
注意:?如果發(fā)現(xiàn)沒(méi)有捕獲到由應(yīng)用程序在異常處理域設(shè)置中引發(fā)的異常,請(qǐng)?jiān)跇?gòu)建應(yīng)用程序或庫(kù)時(shí)確認(rèn)未指定該-no_compact_unwind標(biāo)志。
64位iOS使用“零成本”異常實(shí)現(xiàn)。在“零成本”系統(tǒng)中,每個(gè)函數(shù)都有其他數(shù)據(jù),這些數(shù)據(jù)描述了在函數(shù)上引發(fā)異常時(shí)如何展開(kāi)堆棧。如果在沒(méi)有展開(kāi)數(shù)據(jù)的堆棧幀上引發(fā)異常,則異常處理將無(wú)法繼續(xù),并且進(jìn)程將停止。可能在堆棧的更上方有一個(gè)異常處理程序,但是如果沒(méi)有一幀的展開(kāi)數(shù)據(jù),則無(wú)法從引發(fā)異常的堆棧幀到達(dá)那里。指定該-no_compact_unwind標(biāo)志意味著您沒(méi)有該代碼的展開(kāi)表,因此您不能在這些函數(shù)之間引發(fā)異常。
另外,如果您在應(yīng)用程序或庫(kù)中包含普通C代碼,則可能需要指定-funwind-tables標(biāo)志以包括該代碼中所有函數(shù)的展開(kāi)表。
線程狀態(tài)
本節(jié)列出了崩潰的線程的線程狀態(tài)。這是寄存器列表及其在執(zhí)行暫停時(shí)的值。讀取崩潰報(bào)告時(shí),不必了解線程狀態(tài),但是您可以使用此信息來(lái)更好地了解崩潰的狀況。
清單12?摘自ARM64設(shè)備的崩潰報(bào)告中的“線程狀態(tài)”部分。
線程0因ARM線程狀態(tài)(64位)而崩潰:
? ? x0:0x0000000000000000 x1:0x000000019ff776c8 x2:0x0000000000000000 x3:0x000000019ff776c8
? ? x4:0x0000000000000000 x5:0x0000000000000001 x6:0x0000000000000000 x7:0x00000000000000d0
? ? x8:0x0000000100023920 x9:0x0000000000000000 x10:0x000000019ff7dff0 x11:0x0000000c0000000f
? x12:0x000000013e63b4d0 x13:0x000001a19ff75009 x14:0x0000000000000000 x15:0x0000000000000000
? x16:0x0000000187b3f1b9 x17:0x0000000181ed488c x18:0x0000000000000000 x19:0x000000013e544780
? x20:0x000000013fa49560 x21:0x0000000000000001 x22:0x000000013fc05f90 x23:0x000000010001e069
? x24:0x0000000000000000 x25:0x000000019ff776c8 x26:0xee009ec07c8c24c7 x27:0x0000000000000020
? x28:0x0000000000000000 fp:0x000000016fdf29e0 lr:0x0000000100017cf8
? ? sp:0x000000016fdf2980 pc:0x0000000100017d14 cpsr:0x60000000
二進(jìn)制圖像
本節(jié)列出了終止時(shí)在進(jìn)程中加載??的二進(jìn)制映像。
清單13?崩潰報(bào)告的二進(jìn)制圖像部分中應(yīng)用程序條目的摘錄。
二進(jìn)制圖像:
0x100060000-0x100073fff TheElements arm64 <2defdbea0c873a52afa458cf14cd169e> /var/containers/Bundle/Application/888C1FA2-3666-4AE2-9E8E-62E2F787DEC1/TheElements.app/TheElements
...
每行包括單個(gè)二進(jìn)制映像的以下詳細(xì)信息:
進(jìn)程中的二進(jìn)制映像的地址空間。
二進(jìn)制文件的二進(jìn)制文件名稱(chēng)或捆綁包標(biāo)識(shí)符(僅適用于macOS)。在來(lái)自macOS的崩潰報(bào)告中,如果二進(jìn)制文件是操作系統(tǒng)的一部分,則前綴(+)。
(僅適用于macOS)二進(jìn)制文件的簡(jiǎn)短版本字符串和捆綁軟件版本,以破折號(hào)分隔。
(僅適用于iOS)二進(jìn)制映像的體系結(jié)構(gòu)。二進(jìn)制文件可以包含多個(gè)“片段”,每個(gè)“片段”都支持一種架構(gòu)。這些片中只有一個(gè)被加載到進(jìn)程中。
一個(gè)唯一標(biāo)識(shí)二進(jìn)制映像的UUID。該值隨二進(jìn)制文件的每次構(gòu)建而變化,并在符號(hào)化崩潰報(bào)告時(shí)用于定位相應(yīng)的dSYM文件。
磁盤(pán)上二進(jìn)制文件的路徑。
了解內(nèi)存不足報(bào)告
當(dāng)檢測(cè)到內(nèi)存不足的情況時(shí),iOS中的虛擬內(nèi)存系統(tǒng)將依靠應(yīng)用程序的協(xié)作來(lái)釋放內(nèi)存。低內(nèi)存通知將作為釋放內(nèi)存的請(qǐng)求發(fā)送到所有正在運(yùn)行的應(yīng)用程序和進(jìn)程,以減少使用的內(nèi)存量。如果仍然存在內(nèi)存壓力,系統(tǒng)可能會(huì)終止后臺(tái)進(jìn)程以減輕內(nèi)存壓力。如果可以釋放足夠的內(nèi)存,則您的應(yīng)用程序?qū)⒗^續(xù)運(yùn)行。如果沒(méi)有,您的應(yīng)用程序?qū)⒈籭OS終止,因?yàn)闆](méi)有足夠的內(nèi)存來(lái)滿(mǎn)足應(yīng)用程序的需求,并且將生成內(nèi)存不足報(bào)告并將其存儲(chǔ)在設(shè)備上。
低內(nèi)存報(bào)告的格式與其他崩潰報(bào)告的不同之處在于,應(yīng)用程序線程沒(méi)有回溯。低內(nèi)存報(bào)告以類(lèi)似于崩潰報(bào)告標(biāo)頭的標(biāo)頭開(kāi)頭。標(biāo)頭后是一組字段,這些字段列出了系統(tǒng)范圍的內(nèi)存統(tǒng)計(jì)信息。記下“?頁(yè)面大小”字段的值。低內(nèi)存報(bào)告中每個(gè)進(jìn)程的內(nèi)存使用情況以?xún)?nèi)存頁(yè)數(shù)為單位進(jìn)行報(bào)告。
內(nèi)存不足報(bào)告中最重要的部分是進(jìn)程表。下表列出了生成低內(nèi)存報(bào)告時(shí)所有正在運(yùn)行的進(jìn)程,包括系統(tǒng)守護(hù)程序。如果某個(gè)流程被“簡(jiǎn)化”,則原因?qū)⒘性?b>[原因]列下。可能由于多種原因而中止流程:
[per-process-limit]:進(jìn)程超過(guò)了系統(tǒng)施加的內(nèi)存限制。系統(tǒng)為所有應(yīng)用程序建立駐留內(nèi)存的每個(gè)進(jìn)程限制。超過(guò)此限制將使該過(guò)程有資格終止。
注意:?擴(kuò)展具有更低的每進(jìn)程內(nèi)存限制。某些技術(shù),例如地圖視圖和SpriteKit,會(huì)帶來(lái)較高的基線內(nèi)存成本,并且可能不適合在擴(kuò)展中使用。
[vm-pageshortage] / [vm-thrashing] / [vm]:由于內(nèi)存壓力,進(jìn)程被終止。
[vnode-limit]:打開(kāi)了太多文件。
注意:?當(dāng)vnode幾乎耗盡時(shí),系統(tǒng)避免殺死最前端的應(yīng)用程序。這意味著您的應(yīng)用程序在后臺(tái)運(yùn)行時(shí),即使不是多余的vnode使用量的來(lái)源,也可能會(huì)終止。
[highwater]:系統(tǒng)守護(hù)程序越過(guò)了高水位標(biāo)記以用于內(nèi)存使用。
[jettisoned]:由于其他一些原因,該過(guò)程被擱置了。
如果您沒(méi)有在應(yīng)用程序/擴(kuò)展名過(guò)程旁邊看到原因,則表明崩潰的原因不是內(nèi)存不足。查找.crash文件(在上一節(jié)中進(jìn)行了介紹)以獲取更多信息。
當(dāng)看到內(nèi)存不足崩潰時(shí),而不是擔(dān)心終止時(shí)代碼的哪個(gè)部分正在執(zhí)行,您應(yīng)該調(diào)查內(nèi)存使用模式以及對(duì)內(nèi)存不足警告的響應(yīng)。在您的應(yīng)用程序中查找內(nèi)存問(wèn)題列出了有關(guān)如何使用泄漏工具發(fā)現(xiàn)內(nèi)存泄漏以及如何使用分配工具的標(biāo)記堆功能避免遺棄內(nèi)存的詳細(xì)步驟。《內(nèi)存使用性能指南》討論了響應(yīng)低內(nèi)存通知的正確方法,以及有效使用內(nèi)存的許多技巧。還建議您檢查WWDC 2010會(huì)話“?使用儀器進(jìn)行高級(jí)內(nèi)存分析”。
重要:?泄漏和分配工具不會(huì)跟蹤所有內(nèi)存使用情況。您需要使用VM Tracker儀器(包含在“儀器分配”模板中)運(yùn)行您的應(yīng)用程序,以查看總內(nèi)存使用情況。默認(rèn)情況下,VM Tracker被禁用。要使用VM Tracker來(lái)分析您的應(yīng)用程序,請(qǐng)單擊儀器,選中“自動(dòng)快照”標(biāo)志,或手動(dòng)按“立即快照”按鈕。