iOS之異常與信號使用場景分析
正文
Crash的主要原因是你的應用收到了未處理的信號。 未處理的信號可能來源于三個地方:kernel(系統(tǒng)內核)、其他進程、以及App本身。 因此,crash異常也分為三種:
- Mach異常:是指底層的內核級異常。用戶態(tài)的開發(fā)者可以直接通過Mach API設置Thread、task、host的異常端口,來捕獲Mach異常。
- Unix信號:又稱BSD信號,如果開發(fā)者沒有捕獲Mach異常,則會被host層的方法ux_exception()將異常轉換為對應的UNIX信號,并通過方法threadsignal()將信號投遞到出錯的線程??梢酝ㄟ^方法singnal(x, SignalHandler)來捕獲single。
- NSException:應用級異常,它是未被捕獲的Objective-C異常,導致程序向自身發(fā)送了SIGABRT信號而崩潰,對于未捕獲的Objective-C異常,是可以通過try catch來捕獲的,或者通過NSSetUncaughtExceptionHandler()機制來捕獲。
異常
Exception Type:
異常的type固定是SIGABRT,其實是CrashReporter在捕獲Exception之后,再調用abort()發(fā)出的信號類型。這個機制也決定了如果是Exception Crash,堆棧就看這里的Last Exception Backtrace:, Crash Thread 里面固定是handleException的堆棧,沒有查看的意義。
Exception Codes:
一般就是 0 at 0x18ac2378,后面這個地址就是發(fā)生異常的對象的地址
特殊的 Exception Code
- 0xdead10cc - Deaklock
我們在掛起之前持有文件鎖或 SQLite 數(shù)據(jù)庫鎖。我們應該在掛起之前釋放鎖
- 0xbaaaaaad - Bad
通過側面和兩個音量按鈕對整個系統(tǒng)進行了 stackshot。
- 0xbad22222 - Bad too (two) many times
可能是 VOIP 應用被頻繁喚起導致的崩潰。也可以注意一下我們的后臺調用網(wǎng)絡的代碼。 如果我們的TCP連接被喚醒太多次(例如 300 秒內喚醒 15 次),就會導致此崩潰。
- 0x8badf00d - Ate (eight) bad food
我們的應用程序執(zhí)行狀態(tài)更改(啟動、關閉、處理系統(tǒng)消息等)花費了太長時間。與看門狗的時間策略發(fā)生沖突(超時)并導致終止。最常見的罪魁禍首是在主線程上進行同步的網(wǎng)絡連接。
- 0xc00010ff - Cool Off
系統(tǒng)檢測的設備發(fā)燙而終止了我們的 App。如果只在少量設備上(幾個)發(fā)生,那就可能是由于硬件的問題,而不是我們 App 問題。但是如果發(fā)生在其他設備上,我們應該使用 Instruments 去檢查我們 App 的耗電量問題。
- 0x2bad45ec - Too bad for security
發(fā)生安全沖突。 如果 Termination Description 顯示為 Process detected doing insecure drawing while in secure mode,則意味著我們的應用嘗試在不允許的情況下進行繪制,例如在鎖定屏幕的情況下。
Triggered by Thread:
發(fā)生Crash的線程
Application Specific Infomation:
Exception的信息,這個是定位異常的關鍵信息
Last Exception Backtrace:
拋出異常的代碼堆棧,如果是異常,就看這個堆棧
主要信號
主要信號有 SIGTERM、SIGABRT、SIGSEGV、SIGBUS、SIGILL、SIGFPT、SIGKILL、SIGTRAP
程序結束(terminate)信號,與SIGKILL不同的是該信號可以被阻塞和處理。通常用來要求程序自己正常退出。iOS中一般不會處理到這個信號
SIGABRT原因
- double free指針,void *ptr = malloc(256); free(ptr);free(ptr);// 重復釋放會導致SIGABRT錯誤
- free沒有初始化的地址或者錯誤的地址,void ptr - (void)0x0000100; free(ptr);//釋放未初始化的地址導致SIGABRT錯誤
- 內存越界,char str2[10]; char *str1 = "askldfjadslfjsalkjfsalkfdj"; strcpy(str2, str1);
- 直接調用abort()
- 直接調用assert()
場景
全局變量賦值的代碼段,被多線程調用同時賦值,上一次賦的值就可能被多個線程釋放
解決方案
刪掉類似的賦值操作或者加鎖
SIGSEGV原因:
- invalid memory access(segmentation fault)
- 無效的內存地址引用信號(常見的野指針訪問,訪問了沒有權限的內存地址,系統(tǒng)內存地址等)
- 非ARC模式下,iOS中經(jīng)常會出現(xiàn)在Delegate對象野指針訪問
- ARC模式下,iOS經(jīng)常會出現(xiàn)在Block代碼塊內強持有可能釋放的對象
場景:
SDWebImageDownloaderOperation 生命周期的管理和錯誤回調是在2個queue, 有可能 self 已經(jīng)進入釋放邏輯,再訪問 self.completeBlock, 再訪問就是無效的。
原因:
多線程訪問或者操作對象、棧溢出。
SIBBUS原因:
- mmap 內存映射訪問超出了??
char *p, tmp; NSString *path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"txt"]; int fd = open(path.UTF8String, O_RDWR); p = (char*)mmap(NULL,FILESIZE, PROT_READ|PROT_WRITE,MAP_SHARED, fd, 0); signal(SIGBUS, handle_sigbus); getchar(); for(int i=0;i<FILESIZE;i++){ tmp = p[i]; } printf("ok\n");
- 訪問未對?的內存地址, int pi = (int)(0x00001111); *pi = 17;
場景:
mmap 映射了?個?件的內存,寫入時越界。
對比:
SIGSGV 訪問的是?效的內存,就是該內存不屬于我們的進程,或者沒有權限,SIGBUS指的是 CPU ?法操作該地址,?部分是沒有對?導致的。
SIGILL原因:
- 執(zhí)??法指令
- 堆棧溢出
典型場景:
iOS 上該問題有可能會隨機產(chǎn)?在任何動態(tài)庫、靜態(tài)庫的?法中,?旦出現(xiàn)之后,應?會?直崩潰
解決方案:
app級別的代碼沒有修改可執(zhí)?段的權限,?法污染代碼段,判斷是蘋果增量的問題,用戶重啟?機
定義:
程序結束接收中?信號,?般exit()會發(fā)?這個信號,當前應用不能捕獲,也無法忽略,OOM,Watchdog最終都是這個異常信號。
- ?時間占?太多 CPU 資源,被系統(tǒng)殺掉
- 應?啟動的時候,在主線程做?時間操作,或者卡死,導致被 watchdog 殺死
- 線程切換過于頻繁,被系統(tǒng)殺掉
- 應?占?過多內存,被 jetsam 殺掉
SIGTRAP原因:
很多系統(tǒng)庫例如 WebKit,libdispatch 等使?了__builtin_trap() ?法去觸發(fā)斷點異常,在debug 模式下,會觸發(fā)調試器斷點,這樣開發(fā)可以實時查看問題,在 release 模式下,應?就會崩潰,然后產(chǎn)? SIGTRAP 信號。
典型場景:
dispatch_group_enter 和 dispatch_group_leave 調?不匹配,如果dispatch_group_leave 多調?了,會觸發(fā) DISPATCH_CLIENT_CRASH,在DISPATCH_CLIENT_CRASH 內部會調?__builtin_trap() 觸發(fā)調式陷阱 。
Mach 異常
Mach異常的好處就是可以捕獲更多的Crash,?如循環(huán)遞歸導致的堆棧溢出crash。原本信號的?式回調會在崩潰的線程??,但是因為循環(huán)遞歸已經(jīng)堆棧溢出了,已經(jīng)沒有環(huán)境來執(zhí)?crash捕獲的邏輯了,但是Mach異常捕獲可以定義單獨的線程來處理Mach異常邏輯。 如何區(qū)分我們看到的?志是Mach異常的呢? Exception Type: 是EXC_打頭的話,就是Mach異常了,后?的Exception Subtype:其實是根據(jù)Exception Type:轉了?下
Exception Type:
- EXC_BAD_ACCESS:內存不能訪問,對應SIGBUS和SIGSEGV
- EXC_BAD_INSTRUCTION:?法的指令,對應捕獲到的SIGILL問題
- EXC_ARITHMETIC:算術運算出錯,對應SIGFPE
- EXC_EMULATION:對應SIGEMT
- EXC_SOFTWARE:軟件出錯,對應SIGSYS,SIGPIPE,SIGABRT,SIGKILL
- EXC_BREAKPOINT:對應SIGTRAP
- EXC_SYSCALL:不常?
- EXC_MACH_SYSCALL:不常?
- EXC_RPC_ALERT:不常?
- EXC_CRASH:對應SIGBART
- EXC_GUARD:?般是?件句柄防護,?如close到了?個內核的fd.
- EXC_RESOURCE:遇到了?些系統(tǒng)資源的限制,?般是CPU過載,線程調度太頻繁,?如iOS中每秒?線程喚醒次數(shù)不能超過150
Abort
Abort 包含哪些場景?
- 內存使?量過?、短時間內申請?量內存,系統(tǒng)發(fā)送signal9(signal9?法通過信號捕獲)強制殺死進程(類似于Android端上的OOM),就是?家常說的Jetsam事件
- 主線程發(fā)?卡死超過?定時間watchdog強制殺死進程(不同系統(tǒng)版本卡死時間不同)
- 啟動超時、后臺切前臺resume超時
- 部分死循環(huán)、遞歸等造成的棧溢出
Abort目標
- 現(xiàn)場及上下?捕獲
- 定位 Abort 的業(yè)務場景、發(fā)?原因
- 基于現(xiàn)場及上下?捕獲數(shù)據(jù)、Abort發(fā)?原因的?法形成?效的?具鏈,?于快速定位線上崩潰率發(fā)?的主因
Abort推導規(guī)則
需要根據(jù)可能導致客戶端崩潰的原因設計推導規(guī)則,并基于線上?戶的 Abort 數(shù)據(jù)快速聚合,從而發(fā)現(xiàn)并解決影響線上穩(wěn)定性的問題
以上就是iOS之異常與信號使用場景分析的詳細內容,更多關于iOS 異常信號的資料請關注腳本之家其它相關文章!
相關文章
IOS開發(fā) 支持https請求以及ssl證書配置詳解
這篇文章主要介紹了IOS開發(fā) 支持https請求以及ssl證書配置詳解的相關資料,需要的朋友可以參考下2017-02-02iOS開發(fā)教程之APP內部切換語言的實現(xiàn)方法
這篇文章主要給大家介紹了關于iOS開發(fā)教程之APP內部切換語言的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2019-02-02iOS開發(fā)創(chuàng)建frame實現(xiàn)window窗口view視圖示例
這篇文章主要為大家介紹了iOS開發(fā)創(chuàng)建frame實現(xiàn)window窗口view視圖示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-05-05