iOS之異常與信號使用場景分析
正文
Crash的主要原因是你的應(yīng)用收到了未處理的信號。 未處理的信號可能來源于三個(gè)地方:kernel(系統(tǒng)內(nèi)核)、其他進(jìn)程、以及App本身。 因此,crash異常也分為三種:
- Mach異常:是指底層的內(nèi)核級異常。用戶態(tài)的開發(fā)者可以直接通過Mach API設(shè)置Thread、task、host的異常端口,來捕獲Mach異常。
- Unix信號:又稱BSD信號,如果開發(fā)者沒有捕獲Mach異常,則會被host層的方法ux_exception()將異常轉(zhuǎn)換為對應(yīng)的UNIX信號,并通過方法threadsignal()將信號投遞到出錯(cuò)的線程??梢酝ㄟ^方法singnal(x, SignalHandler)來捕獲single。
- NSException:應(yīng)用級異常,它是未被捕獲的Objective-C異常,導(dǎo)致程序向自身發(fā)送了SIGABRT信號而崩潰,對于未捕獲的Objective-C異常,是可以通過try catch來捕獲的,或者通過NSSetUncaughtExceptionHandler()機(jī)制來捕獲。
異常
Exception Type:
異常的type固定是SIGABRT,其實(shí)是CrashReporter在捕獲Exception之后,再調(diào)用abort()發(fā)出的信號類型。這個(gè)機(jī)制也決定了如果是Exception Crash,堆棧就看這里的Last Exception Backtrace:, Crash Thread 里面固定是handleException的堆棧,沒有查看的意義。
Exception Codes:
一般就是 0 at 0x18ac2378,后面這個(gè)地址就是發(fā)生異常的對象的地址
特殊的 Exception Code
- 0xdead10cc - Deaklock
我們在掛起之前持有文件鎖或 SQLite 數(shù)據(jù)庫鎖。我們應(yīng)該在掛起之前釋放鎖
- 0xbaaaaaad - Bad
通過側(cè)面和兩個(gè)音量按鈕對整個(gè)系統(tǒng)進(jìn)行了 stackshot。
- 0xbad22222 - Bad too (two) many times
可能是 VOIP 應(yīng)用被頻繁喚起導(dǎo)致的崩潰。也可以注意一下我們的后臺調(diào)用網(wǎng)絡(luò)的代碼。 如果我們的TCP連接被喚醒太多次(例如 300 秒內(nèi)喚醒 15 次),就會導(dǎo)致此崩潰。
- 0x8badf00d - Ate (eight) bad food
我們的應(yīng)用程序執(zhí)行狀態(tài)更改(啟動、關(guān)閉、處理系統(tǒng)消息等)花費(fèi)了太長時(shí)間。與看門狗的時(shí)間策略發(fā)生沖突(超時(shí))并導(dǎo)致終止。最常見的罪魁禍?zhǔn)资窃谥骶€程上進(jìn)行同步的網(wǎng)絡(luò)連接。
- 0xc00010ff - Cool Off
系統(tǒng)檢測的設(shè)備發(fā)燙而終止了我們的 App。如果只在少量設(shè)備上(幾個(gè))發(fā)生,那就可能是由于硬件的問題,而不是我們 App 問題。但是如果發(fā)生在其他設(shè)備上,我們應(yīng)該使用 Instruments 去檢查我們 App 的耗電量問題。
- 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è)堆棧
主要信號
主要信號有 SIGTERM、SIGABRT、SIGSEGV、SIGBUS、SIGILL、SIGFPT、SIGKILL、SIGTRAP
程序結(jié)束(terminate)信號,與SIGKILL不同的是該信號可以被阻塞和處理。通常用來要求程序自己正常退出。iOS中一般不會處理到這個(gè)信號
SIGABRT原因
- double free指針,void *ptr = malloc(256); free(ptr);free(ptr);// 重復(fù)釋放會導(dǎo)致SIGABRT錯(cuò)誤
- free沒有初始化的地址或者錯(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()
場景
全局變量賦值的代碼段,被多線程調(diào)用同時(shí)賦值,上一次賦的值就可能被多個(gè)線程釋放
解決方案
刪掉類似的賦值操作或者加鎖
SIGSEGV原因:
- invalid memory access(segmentation fault)
- 無效的內(nèi)存地址引用信號(常見的野指針訪問,訪問了沒有權(quán)限的內(nèi)存地址,系統(tǒng)內(nèi)存地址等)
- 非ARC模式下,iOS中經(jīng)常會出現(xiàn)在Delegate對象野指針訪問
- ARC模式下,iOS經(jīng)常會出現(xiàn)在Block代碼塊內(nèi)強(qiáng)持有可能釋放的對象
場景:
SDWebImageDownloaderOperation 生命周期的管理和錯(cuò)誤回調(diào)是在2個(gè)queue, 有可能 self 已經(jīng)進(jìn)入釋放邏輯,再訪問 self.completeBlock, 再訪問就是無效的。
原因:
多線程訪問或者操作對象、棧溢出。
SIBBUS原因:
- mmap 內(nèi)存映射訪問超出了??
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");
- 訪問未對?的內(nèi)存地址, int pi = (int)(0x00001111); *pi = 17;
場景:
mmap 映射了?個(gè)?件的內(nèi)存,寫入時(shí)越界。
對比:
SIGSGV 訪問的是?效的內(nèi)存,就是該內(nèi)存不屬于我們的進(jìn)程,或者沒有權(quán)限,SIGBUS指的是 CPU ?法操作該地址,?部分是沒有對?導(dǎo)致的。
SIGILL原因:
- 執(zhí)??法指令
- 堆棧溢出
典型場景:
iOS 上該問題有可能會隨機(jī)產(chǎn)?在任何動態(tài)庫、靜態(tài)庫的?法中,?旦出現(xiàn)之后,應(yīng)?會?直崩潰
解決方案:
app級別的代碼沒有修改可執(zhí)?段的權(quán)限,?法污染代碼段,判斷是蘋果增量的問題,用戶重啟?機(jī)
定義:
程序結(jié)束接收中?信號,?般exit()會發(fā)?這個(gè)信號,當(dāng)前應(yīng)用不能捕獲,也無法忽略,OOM,Watchdog最終都是這個(gè)異常信號。
- ?時(shí)間占?太多 CPU 資源,被系統(tǒng)殺掉
- 應(yīng)?啟動的時(shí)候,在主線程做?時(shí)間操作,或者卡死,導(dǎo)致被 watchdog 殺死
- 線程切換過于頻繁,被系統(tǒng)殺掉
- 應(yīng)?占?過多內(nèi)存,被 jetsam 殺掉
SIGTRAP原因:
很多系統(tǒng)庫例如 WebKit,libdispatch 等使?了__builtin_trap() ?法去觸發(fā)斷點(diǎn)異常,在debug 模式下,會觸發(fā)調(diào)試器斷點(diǎn),這樣開發(fā)可以實(shí)時(shí)查看問題,在 release 模式下,應(yīng)?就會崩潰,然后產(chǎn)? SIGTRAP 信號。
典型場景:
dispatch_group_enter 和 dispatch_group_leave 調(diào)?不匹配,如果dispatch_group_leave 多調(diào)?了,會觸發(fā) DISPATCH_CLIENT_CRASH,在DISPATCH_CLIENT_CRASH 內(nèi)部會調(diào)?__builtin_trap() 觸發(fā)調(diào)式陷阱 。
Mach 異常
Mach異常的好處就是可以捕獲更多的Crash,?如循環(huán)遞歸導(dǎo)致的堆棧溢出crash。原本信號的?式回調(diào)會在崩潰的線程??,但是因?yàn)檠h(huán)遞歸已經(jīng)堆棧溢出了,已經(jīng)沒有環(huán)境來執(zhí)?crash捕獲的邏輯了,但是Mach異常捕獲可以定義單獨(dú)的線程來處理Mach異常邏輯。 如何區(qū)分我們看到的?志是Mach異常的呢? Exception Type: 是EXC_打頭的話,就是Mach異常了,后?的Exception Subtype:其實(shí)是根據(jù)Exception Type:轉(zhuǎn)了?下
Exception Type:
- EXC_BAD_ACCESS:內(nèi)存不能訪問,對應(yīng)SIGBUS和SIGSEGV
- EXC_BAD_INSTRUCTION:?法的指令,對應(yīng)捕獲到的SIGILL問題
- EXC_ARITHMETIC:算術(shù)運(yùn)算出錯(cuò),對應(yīng)SIGFPE
- EXC_EMULATION:對應(yīng)SIGEMT
- EXC_SOFTWARE:軟件出錯(cuò),對應(yīng)SIGSYS,SIGPIPE,SIGABRT,SIGKILL
- EXC_BREAKPOINT:對應(yīng)SIGTRAP
- EXC_SYSCALL:不常?
- EXC_MACH_SYSCALL:不常?
- EXC_RPC_ALERT:不常?
- EXC_CRASH:對應(yīng)SIGBART
- EXC_GUARD:?般是?件句柄防護(hù),?如close到了?個(gè)內(nèi)核的fd.
- EXC_RESOURCE:遇到了?些系統(tǒng)資源的限制,?般是CPU過載,線程調(diào)度太頻繁,?如iOS中每秒?線程喚醒次數(shù)不能超過150
Abort
Abort 包含哪些場景?
- 內(nèi)存使?量過?、短時(shí)間內(nèi)申請?量內(nèi)存,系統(tǒng)發(fā)送signal9(signal9?法通過信號捕獲)強(qiáng)制殺死進(jìn)程(類似于Android端上的OOM),就是?家常說的Jetsam事件
- 主線程發(fā)?卡死超過?定時(shí)間watchdog強(qiáng)制殺死進(jìn)程(不同系統(tǒng)版本卡死時(shí)間不同)
- 啟動超時(shí)、后臺切前臺resume超時(shí)
- 部分死循環(huán)、遞歸等造成的棧溢出
Abort目標(biāo)
- 現(xiàn)場及上下?捕獲
- 定位 Abort 的業(yè)務(wù)場景、發(fā)?原因
- 基于現(xiàn)場及上下?捕獲數(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)定性的問題
以上就是iOS之異常與信號使用場景分析的詳細(xì)內(nèi)容,更多關(guān)于iOS 異常信號的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
iOS布局渲染之UIView方法的調(diào)用時(shí)機(jī)詳解
在你剛開始開發(fā) iOS 應(yīng)用時(shí),最難避免或者是調(diào)試的就是和布局相關(guān)的問題,下面這篇文章主要給大家介紹了關(guān)于iOS布局渲染之UIView方法調(diào)用時(shí)機(jī)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2018-07-07
iOS 委托與文本輸入(內(nèi)容根據(jù)iOS編程編寫)
這篇文章主要介紹了iOS 委托與文本輸入(內(nèi)容根據(jù)iOS編程編寫) 的相關(guān)資料,需要的朋友可以參考下2016-09-09
IOS實(shí)現(xiàn)驗(yàn)證碼倒計(jì)時(shí)功能(一)
這篇文章主要介紹了IOS實(shí)現(xiàn)驗(yàn)證碼倒計(jì)時(shí)功能,點(diǎn)擊獲取驗(yàn)證碼,進(jìn)入時(shí)間倒計(jì)時(shí),感興趣的小伙伴們可以參考一下2016-01-01
iOS實(shí)現(xiàn)微信/QQ顯示最近拍攝圖片的功能實(shí)例代碼
如果你剛剛拍攝了圖片,在使用微信/QQ發(fā)生消息時(shí)會顯示“你可能要發(fā)送的圖片”,這個(gè)功能非常人性化,怎么實(shí)現(xiàn)的呢?下面小編給大家分享iOS實(shí)現(xiàn)微信/QQ顯示最近拍攝圖片的功能實(shí)例代碼,一起看看吧2017-03-03
iOS內(nèi)存錯(cuò)誤EXC_BAD_ACCESS的解決方法
iOS開發(fā),最郁悶的莫過于程序毫無征兆地就崩潰了,用bt命令打出調(diào)用棧,給出的是一堆系統(tǒng)EXC_BAD_ACCESS的信息,根本沒辦法定位問題出現(xiàn)在哪里2013-06-06
解決iOS11圖片下拉放大出現(xiàn)信號欄白條的bug問題
這篇文章主要介紹了iOS11圖片下拉放大出現(xiàn)信號欄白條的bug問題,需要的朋友參考下吧2017-09-09
IOS設(shè)計(jì)模式之組合設(shè)計(jì)模式
組合模式,Composite Pattern,是一個(gè)非常巧妙的模式。幾乎所有的面向?qū)ο笙到y(tǒng)都應(yīng)用到了組合模式,接下來通過本文給大家介紹IOS設(shè)計(jì)模式之組合設(shè)計(jì)模式,需要的朋友參考下2016-02-02
iOS程序開發(fā)中設(shè)置UITableView的全屏分隔線的方法(不畫線)
ableView是app開發(fā)中常用到的控件,功能很強(qiáng)大,多用于數(shù)據(jù)的顯示。下面給大家介紹設(shè)置UITableView的全屏分隔線的兩種方法2016-04-04

