程序的異常捕獲:
Crash日志記錄的時候是將Crash發生時刻,函數的調用棧,以及線程等信息寫入文件。
01-Crash文件的解析
今天就跟大家一起聊聊 iOS Crash文件的組成以及常用的分析工具。
一、Crash文件結構
當程序運行Crash的時候,系統會把運行的最后時刻的運行信息記錄下來,存儲到一個文件中,也就是我們所說的
Crash文件。iOS的Crash日志通常由以下6各部分組成。
1、Process Information(進程信息)
Incident Idnetifier-崩潰報告的唯一標識符,不同的CrashCrashReporter Key-設備標識相對應的唯一鍵值(並非真正的設備的UDID,蘋果為了保護用戶隱私iOS6以后已經無法
獲取)。通常同一個設備上同一版本的App發生Crash時,該值都是一樣的。
Hardware Model - 代表發生Crash的設備類型,上圖中的“iPad4,4”代表iPad Air
Process - 代表Crash的進程名稱,通常都是我們的App的名字, []里面是當時進程的ID
Path - 可執行程序在手機上的存儲位置,注意路徑時到XXX.app/XXX,XXX.app其實是作為一個Bundle的,真正的可 執行文件其實是Bundle里面的XXX,感興趣的可以自己查一下相關資料,有機會我后面也會介紹到
Identifier-你的App的Indentifier,通常為“com.xxx.yyy”,xxx代表你們公司的域名,yyy代表某一個App
Version-當前App的版本號,由Info.plist中的兩個字段組成,CFBundleShortVersionString and CFBundleVersion
Code Type-當前App的CPU架構
Parent Process-當前進程的父進程,由於iOS中App通常都是單進程的,一般父進程都是launchd
2、Basic Information
Date/Time-Crash發生的時間,可讀的字符串
OS Version-系統版本,()內的數字代表的時Bulid號
Report Version-Crash日志的格式,目前基本上都是104,不同的version里面包含的字段可能有不同
3、Exception(非常重要)
Exception Type-異常類型
Exception Subtype-異常子類型
Crashed Thread-發生異常的線程號
4、Thread Backtrace
發生Crash的線程的Crash調用棧,從上到下分別代表調用順序,最上面的一個表示拋出異常的位置,依次往下可以看 到API的調用順序。上圖的信息表明本次Crash出現xxxViewController的323行,出錯的函數調用為 orderCountLoadFailed。
5、Thread State
Crash時發生時刻,線程的狀態,通常我們根據Crash棧即可獲取到相關信息,這部分一般不用關心。
6、Binary Images
Crash時刻App加載的所有的庫,其中第一行是Crash發生時我們App可執行文件的信息,可以看出為armv7,可執行 文件的包得uuid位c0f......cd65,解析Crash的時候dsym文件的uuid必須和這個一樣才能完成Crash的符號化解析。
二、分析Crash來源
通常來說,crash產生來源於兩種問題:違反iOS系統規則導致的crash和App代碼邏輯 BUG導致的crash,下面分別對他們進行分析。
違反iOS系統規則產生crash的三種類型:
1>內存報警閃退
當iOS檢測到內存過低時,它的VM系統會發出低內存警告通知,嘗試回收一些內存;如果情況沒有得到足夠的改善, iOS會終止后台應用以回收更多內存;最后,如果內存還是不足,那么正在運行的應用可能會被終止掉。在Debug模 式下,可以主動將客戶端執行的動作邏輯寫入一個log文件中,這樣程序童鞋可以將內存預警的邏輯寫入該log文件, 當發生如下截圖中的內存報警時,就是提醒當前客戶端性能內存吃緊,可以通過Instruments工具中的Allocations 和 Leaks模塊庫來發現內存分配問題和內存泄漏問題。
2>響應超時
當應用程序對一些特定的事件(比如啟動、掛起、恢復、結束)響應不及時,蘋果的Watchdog機制會把應用程序干 掉,並生成一份相應的crash日志。這些事件與下列UIApplicationDelegate方法相對應,當遇到Watchdog日志時,可 以檢查上圖中的幾個方法是否有比較重的阻塞UI的動作。
application:didFinishLaunchingWithOptions: 2 applicationWillResignActive:3 applicationDidEnterBackground:4 applicationWillEnterForeground: 5 applicationDidBecomeActive: 6 applicationWillTerminate:
3>用戶強制退出
一看到“用戶強制退出”,首先可能想到的雙擊Home鍵,然后關閉應用程序。不過這種場景一般是不會產生crash日志 的,因為雙擊Home鍵后,所有的應用程序都處於后台狀態,而iOS隨時都有可能關閉后台進程,當應用阻塞界面並停 止響應時這種場景才會產生crash日志。這里指的“用戶強制退出”場景,是稍微比較復雜點的操作:先按住電源鍵,直 到出現“滑動關機”的界面時,再按住Home鍵,這時候當前應用程序會被終止掉,並且產生一份相應事件的crash日 志。
應用邏輯的Bug
大多數閃退崩潰日志的產生都是因為應用中的Bug,這種Bug的錯誤種類有很多,比如:
SEGV:(Segmentation Violation,段違例),無效內存地址,比如空指針,未初始化指針,棧溢出等; SIGABRT:收到Abort信號,可能自身調用abort()或者收到外部發送過來的信號; SIGBUS:總線錯誤。與SIGSEGV不同的是,SIGSEGV訪問的是無效地址(比如虛存映射不到物理內存),而 SIGBUS訪問的是有效地址,但總線訪問異常(比如地址對齊問題); SIGILL:嘗試執行非法的指令,可能不被識別或者沒有權限;
SIGFPE:Floating Point Error,數學計算相關問題(可能不限於浮點計算),比如除零操作; SIGPIPE:管道另一端沒有進程接手數據;
常見的崩潰原因基本都是代碼邏輯問題或資源問題,比如數組越界,訪問野指針或者資源不存在,或資源大小寫錯誤
等。
三、獲取Crash的途徑
1、本機
通過xCode連接測試機器,直接在Device中即可讀取到該機器上發生的所有Crash log。
2、itunes connect通過itunes connect后台獲取到用戶上報的Crash日志。
3、第三方的Crash收集系統
有很多優秀的第三方Crash收集系統大大的方便了我們收集Crash,甚至還帶了符號化Crash日志的功能。比較常用的 有Crashlytics,Flurry等。