這份crash日誌記錄着應用程序崩潰時的信息,一般包括着每個運行線程的棧調用信息(低內存閃退日誌例外),對於開發者定位問題很是有幫助。
假設設備就在身邊,可以鏈接設備,打開Xcode - Window - Organizer,在左側面板中選擇Device Logs(可以選擇詳細設備的Device Logs或者Library下所有設備的Device Logs),而後依據時間排序查看設備上的crash日誌。這是開發、測試階段最經常採用的方式。
假設應用程序已經提交到App Store公佈,用戶已經安裝使用了,那麼開發人員可以經過iTunes Connect(Manage Your Applications - View Details - Crash Reports)獲取用戶的crash日誌。只是這並不是100%有效的,而且大多數開發人員並不依賴於此,因爲這需要用戶設備容許上傳相關信息。詳情可參見iOS: Providing Apple with diagnostics and usage information摘要。
考慮到並不是所有iPhone用戶都贊成本身主動發送診斷報告(crash日誌),而且對於部分提交到Apple得crash日誌,開發人員還需要手動去拉取,而後找到相應的符號文件進行解析——這是一件很是繁瑣的事情。因此實際項目開發中。一般接入現有的crash收集工具(參考1,參考2)。或者本身編寫一個進行本身主動化收集、解析和統計彙總。
2、怎樣解析crash日誌
當得到一份crash日誌時,咱們需要將初始展現的十六進制地址等原始信息映射爲源碼級別的方法名稱和代碼行數,使其對開發者可讀。數據庫
這個過程稱爲符號化解析。要成功地符號化解析一份crash日誌,咱們需要有相應的應用程序二進制文件以及符號(.dSYM)文件。
假設處於開發調試階段。一般Xcode都能匹配到crash日誌相應的二進制文件和符號文件,因此能夠幫咱們本身主動解析。
假設處於測試階段,測試人員已經安裝了不一樣的版本號(比方alpha、beta版本號),那麼需要保存好相應版本號的二進制文件和符號文件。以便在應用程序崩潰時對crash日誌進行解析。對於這樣的場景下產生的crash日誌。僅僅需要將.crash文件、.app文件和.dSYM文件三者放在同一個文件夾下,而後將.crash文件拖放到Xcode - Window - Organizer中左側面板Library下的Device Logs中,就能夠進行解析。
假設要提交公佈,那麼咱們通常會先運行Clean。再Build。最後經過Product - Archive來打包。這樣。Xcode會將二進制文件和符號文件歸檔在一塊兒。可以經過Organizer中的Archives進行瀏覽。數組
這裏是一份關於怎樣解析crash日誌的討論:http://stackoverflow.com/questions/1460892/symbolicating-iphone-app-crash-reports 。
3、怎樣分析crash日誌
在分析一份crash日誌以前,假設開發者對於常見的錯誤類型有所瞭解,那定是極好的。緩存
crash日誌的產生來源於兩種問題:違反iOS策略被幹掉,以及自身的代碼bug。
1. iOS策略
1.1 低內存閃退
前面提到大多數crash日誌都包括着運行線程的棧調用信息,但是低內存閃退日誌除外,這裏就先看看低內存閃退日誌是什麼樣的。
咱們使用Xcode 5和iOS 7的設備模擬一次低內存閃退。而後經過Organizer查看產生的crash日誌,可以發現Process和Type都爲Unknown:
而詳細的日誌內容例如如下:
第一部分是崩潰信息。包含識別標識、軟硬件信息和時間信息等。
第二部分是內存頁分配信息,以及當前佔用內存最多的進程。上圖中爲crashTypeDemo。
第三部分是詳細的進程列表,描寫敘述着每個進程使用內存的狀況以及當前狀態。在較早的版本號中可以在某些進程後面看到「jettisoned」字樣,代表這些進程使用過多內存被終止了。而現在咱們看到的是「vm-pageshortage」字樣。
當iOS檢測到內存太低時,它(的VM系統)會發出低內存警告通知,嘗試回收一些內存。假設狀況沒有獲得足夠的改善,iOS會終止後臺應用以回收不少其它內存;最後。假設內存仍是不足,那麼正在執行的應用可能會被終止掉。
因此,咱們的應用應該合理地響應系統拋出來的低內存警告通知,對一些緩存數據和可又一次建立的對象進行釋放。同一時候要避免出現內存泄露等問題。
低內存閃退是由iOS策略決定終止應用程序執行的,相同基於iOS策略的還有Watchdog超時和用戶強制退出。
1.2 Watchdog超時
Apple的iOS Developer Library站點上,QA1693文檔中描寫敘述了Watchdog機制,包含生效場景和表現。假設咱們的應用程序對一些特定的UI事件(比方啓動、掛起、恢復、結束)響應不及時,Watchdog會把咱們的應用程序幹掉,並生成一份響應的crash報告。安全
這份crash報告的有趣之處在於異常代碼:「0x8badf00d」。即「ate bad food」。
假設說特定的UI事件比較抽象。那麼用代碼來直接描寫敘述的話,相應的就是(建立一個project時Xcode本身主動生成的)UIApplicationDelegate的幾個方法:
因此當遇到Watchdog日誌時。可以檢查下上圖幾個方法是否有比較重的堵塞UI的動做。網絡
QA1693舉的樣例是在主線程進行同步網絡請求。多線程
假設咱們是在公司的Wifi環境下使用則一切順利。但當應用程序公佈出去面向很是大範圍的用戶。在各類網絡環境下執行。則不可避免地會出現一片Watchdog超時報告。app
還有一種可能出現故障的場景就是數據量比較大的狀況下進行的數據庫版本號遷移(相同是在主線程上),這也是促使我寫這篇總結的一個直接因素。
1.3 用戶強制退出
一看到「用戶強制退出」。首先可能想到的雙擊Home鍵。而後關閉應用程序。只是這樣的場景是不會產生crash日誌的,因爲雙擊Home鍵後,所有的應用程序都處於後臺狀態。而iOS隨時都有可能關閉後臺進程,因此這樣的場景沒有crash日誌。iphone
還有一種場景是用戶同一時候按住電源鍵和Home鍵。讓iPhone從新啓動。工具
這樣的場景會產生日誌(僅驗證過一次),但並不針對特定應用程序。
這裏指的「用戶強制退出」場景,是略微比較複雜點的操做:先按住電源鍵。直到出現「滑動關機」的界面時,再按住Home鍵,這時候當前應用程序會被終止掉,並且產生一份對應事件的crash日誌。post
一般。用戶應該是遇到應用程序卡死,並且影響到了iOS響應,纔會進行這種操做——只是感受這操做好高級,因此這種crash日誌應該比較少見。
2. 常見錯誤標識
2.1 Exception codes
上面「用戶強制退出」的crash日誌中的Exception Codes是「0xdeadfa11」,再上面「Watchdog超時」的crash日誌中的Exception Codes是「0x8badf00d」,這些都是特有的Exception codes。
依據官方文檔描寫敘述,至少有下面幾種特定異常代碼:
0x8badf00d錯誤碼:Watchdog超時。意爲「ate bad food」。
0xdeadfa11錯誤碼:用戶強制退出,意爲「dead fall」。
0xbaaaaaad錯誤碼:用戶按住Home鍵和音量鍵。獲取當前內存狀態,不表明崩潰。
0xbad22222錯誤碼:VoIP應用(因爲太頻繁?)被iOS幹掉。
0xc00010ff錯誤碼:因爲太燙了被幹掉。意爲「cool off」。
0xdead10cc錯誤碼:因爲在後臺時仍然佔領系統資源(比方通信錄)被幹掉,意爲「dead lock」。
2.2 Exception types
查看咱們的crash分析報告郵件,會發現最經常遇到的錯誤類型是SEGV(Segmentation Violation。段違例)。代表內存操做不當,比方訪問一個沒有權限的內存地址。
當咱們收到SIGSEGV信號時。可以往下面幾個方面考慮:
訪問無效內存地址,比方訪問Zombie對象;
嘗試往僅僅讀區域寫數據;
解引用空指針。
使用未初始化的指針。
棧溢出;
此外,還有其餘常見信號:
SIGABRT:收到Abort信號,可能自身調用abort()或者收到外部發送過來的信號;
SIGBUS:總線錯誤。
與SIGSEGV不一樣的是,SIGSEGV訪問的是無效地址(比方虛存映射不到物理內存),而SIGBUS訪問的是有效地址。但總線訪問異常(比方地址對齊問題)。
SIGILL:嘗試運行非法的指令,可能不被識別或者沒有權限;
SIGFPE:Floating Point Error。數學計算相關問題(可能不限於浮點計算)。比方除零操做;
SIGPIPE:管道還有一端沒有進程接手數據;
3. 代碼bug
此外,比較常見的崩潰基本都源於代碼bug,比方數組越界、插空、多線程安全性、訪問野指針、發送未實現的selector等。
假設引入Core Data。則又有另一些常見問題。只是這是還有一個話題了。
遇到這些bug時,都有比較清楚的錯誤緣由說明,比方「index 0 beyond bounds for empty array」等。
需要略微注意點的是多線程問題,當一時找不到解決思路時。最好仍是往多線程方面考慮下。