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