iOS端崩潰問題定位總結(jié)

前言

崩潰問題修復(fù)是每一個(gè)客戶端開發(fā)者治理的重難點(diǎn),一般崩潰有三道程序監(jiān)防:1、程序員代碼編程規(guī)范化及Codereview ;2、程序員自測及測試部門同事測試;3、線上檢測工具bugly、Firebase監(jiān)測。崩潰修復(fù)是一個(gè)長期復(fù)雜的過程,程序員治理優(yōu)化程序的過程中,同時(shí)也是提高自身能力和了解更廣泛知識(shí)的過程。要想解決崩潰,首先就要學(xué)會(huì)定位線上崩潰問題,本文就總結(jié)分享了開發(fā)中定位崩潰問題的幾種方法和大家做個(gè)分享。

崩潰問題定位

最重要的三個(gè)文件

  1. dSYM
  2. .crash / .ips 文件
  3. .app

并將三文件整理在一個(gè)文件夾中
流程:準(zhǔn)備三文件 - > 符號化 -> 生成可直觀的文件

dSYM文件獲取

dSYM 是保存 16 進(jìn)制函數(shù)地址映射信息的中轉(zhuǎn)文件,我們調(diào)試的 symbols 都會(huì)包含在這個(gè)文件中,并且每次編譯項(xiàng)目的時(shí)候都會(huì)生成一個(gè)新的 dSYM 文件,位于 /Users/<用戶名>/Library/Developer/Xcode/Archives 目錄下

一般開發(fā)者在完成一個(gè)版本后,就要遷出一個(gè)版本出來。選擇真機(jī)或選擇generic iOS Device, Product -> Archive,隨后

XCode -> Window ->Organizer -> XXArchive文件 -> Show in Finder -> 顯示包內(nèi)容 -> dSYMs -> ***.app.dSYM

一般使用bugly線上監(jiān)測,還應(yīng)把該文件上傳到bugly上幫助定位問題,上傳腳本如下:
dsym文件和bugly文件放在同一路徑下
java -jar buglyqq-upload-symbol.jar -appid *** -appkey **** -bundleid com...* -version 3.. -platform IOS -inputSymbol ..dSYM

若想上傳app內(nèi)引用的其他庫的符號表,以方便查找是不是三方庫的原因,可把..dSYM 替換成對應(yīng)的三方庫dsym,如:***.framework.dSYM 即可</pre>

|

.app文件獲取

XCode -> Window ->Organizer -> XXArchive文件 -> Show in Finder -> 顯示包內(nèi)容 ->Products -> Applications -> *.app

.crash文件獲取

1)手機(jī)連接Mac獲取

XCode -> Window ->Devices and simulators -> view Device Logs
搜索你app的名稱,即可找到真機(jī)產(chǎn)生的crash。

2)參與TestFight與上線共享crash

崩潰時(shí)可以直觀的在XCode查看crash的代碼行。

設(shè)備設(shè)置: 設(shè)置 -> 隱私 -> 與應(yīng)用開發(fā)者共享。
獲取報(bào)告:iTunes Connect ->Manage Your Applications -> View Details -> Crash Reports。導(dǎo)出即可。

定位方法

1、通過.dSYM符號表手動(dòng)分析定位

下面是報(bào)錯(cuò)的堆棧信息:

10 **** 0x00000001052119b4 0x0000000104cd4000 + 5495220

如何分析出第7行的地址指向哪個(gè)方法呢?

終端執(zhí)行如下指令

|

atos -arch arm64 -o ***.app.dSYM/Contents/Resources/DWARF/*** -l 0x0000000104cd40000x0000000105212c48

|

arm64:cpu架構(gòu),發(fā)生報(bào)錯(cuò)的APP的手機(jī)的cpu架構(gòu),可以通過手機(jī)型號去查詢確認(rèn)。

.app.dSYM/Contents/Resources/DWARF/:其中是APP的名字,導(dǎo)出符號表默認(rèn)的,后面的路徑是固定的,只要將替換成你的APP名字即可。(需要 cd 到符號表的文件目錄下)

0x0000000104cd4000 + 5499976:0x0000000104cd4000表示默認(rèn)Slide Address,5499976表示偏移量。

0x0000000105212c48:表示錯(cuò)誤信息內(nèi)存地址。

注意這兩個(gè)地址的先后順序。

執(zhí)行結(jié)果如下:

|

MacBook`` test % atos -arch arm64 -o ***.app.dSYM/Contents/Resources/DWARF/*** -l 0x0000000104cd4000 0x0000000105212c48
-[take hold:] (socket:686)

|

得出-[socket onSocket:didReadData:withTag:]代碼位置。

分析輔助工具

dSYM分析工具可以幫助定位

https://github.com/answer-huang/dSYMTools

[圖片上傳失敗...(image-2f1457-1684396669921)]

2、通過hooper 反匯編定位

當(dāng)發(fā)生Unix 信號的崩潰時(shí)不好定位問題,可借助hooper反編譯來定位

10 *** 0x00000001052119b4 0x0000000104cd4000 + 5495220

由于是線上的崩潰,在拿到 xxx.xcarchive 包之后,把包里面的二進(jìn)制文件拖進(jìn) hopper ,選擇 Arm64 架構(gòu)。接下來我們就可以分析跳轉(zhuǎn)到具體的崩潰位置了,剛好崩潰的線程有包含我們的項(xiàng)目代碼;

0x0000000104cd4000 是項(xiàng)目的基地址,5499976 是十進(jìn)制的偏移量,而這個(gè) 0x0000000105212c48 則是崩潰地址,剛好是 0x0000000104cd4000 + 5499976 的結(jié)果。

所以,我們下面要做的就是跳轉(zhuǎn)到 0x0000000105212c48 這個(gè)崩潰地址看看響應(yīng)的匯編代碼。

  1. hopper -> Modify -> Change File Base Address... ,然后把基地址 0x0000000104cd4000 輸入,重新 Rebase 一下。

  2. hopper -> Navigate -> Go to Address or Symbol... ,輸入 0x0000000105212c48 這個(gè)地址,然后 go 到對應(yīng)的崩潰地址

通過上述步驟可以定位大概代碼位置,然后根據(jù)業(yè)務(wù)推斷問題出錯(cuò)點(diǎn),再結(jié)合修改即可了。

常見崩潰問題

1)Mach 異常

最底層的內(nèi)核級異常。用戶態(tài)的開發(fā)者可以直接通過Mach API設(shè)置thread,task,host的異常端口,來捕獲Mach異常。

新建一個(gè)監(jiān)控線程,在監(jiān)控線程中監(jiān)聽 Mach 異常并處理異常信息。主要的步奏如下圖:

2)Unix信號

又稱BSD 信號,如果開發(fā)者沒有捕獲Mach異常,則會(huì)被host層的方法ux_exception()將異常轉(zhuǎn)換為對應(yīng)的UNIX信號,并通過方法threadsignal()將信號投遞到出錯(cuò)線程。可以通過方法signal(x, SignalHandler)來捕獲signal。

Unix Signal 其實(shí)是由 Mach port 拋出的信號轉(zhuǎn)化的,大致信號:

  • SIGHUP
    本信號在用戶終端連接(正?;蚍钦?結(jié)束時(shí)發(fā)出, 通常是在終端的控制進(jìn)程結(jié)束時(shí), 通知同一session內(nèi)的各個(gè)作業(yè), 這時(shí)它們與控制終端不再關(guān)聯(lián)。

  • SIGINT
    程序終止(interrupt)信號, 在用戶鍵入INTR字符(通常是Ctrl-C)時(shí)發(fā)出,用于通知前臺(tái)進(jìn)程組終止進(jìn)程。

  • SIGQUIT
    和SIGINT類似, 但由QUIT字符(通常是Ctrl-)來控制. 進(jìn)程在因收到SIGQUIT退出時(shí)會(huì)產(chǎn)生core文件, 在這個(gè)意義上類似于一個(gè)程序錯(cuò)誤信號。

  • SIGABRT
    調(diào)用abort函數(shù)生成的信號。
    SIGABRT is a BSD signal sent by an application to itself when an NSException or obj_exception_throw is not caught.

  • SIGBUS
    非法地址, 包括內(nèi)存地址對齊(alignment)出錯(cuò)。比如訪問一個(gè)四個(gè)字長的整數(shù), 但其地址不是4的倍數(shù)。它與SIGSEGV的區(qū)別在于后者是由于對合法存儲(chǔ)地址的非法訪問觸發(fā)的(如訪問不屬于自己存儲(chǔ)空間或只讀存儲(chǔ)空間)。

  • SIGFPE
    在發(fā)生致命的算術(shù)運(yùn)算錯(cuò)誤時(shí)發(fā)出. 不僅包括浮點(diǎn)運(yùn)算錯(cuò)誤, 還包括溢出及除數(shù)為0等其它所有的算術(shù)的錯(cuò)誤。

  • SIGKILL
    用來立即結(jié)束程序的運(yùn)行. 本信號不能被阻塞、處理和忽略。如果管理員發(fā)現(xiàn)某個(gè)進(jìn)程終止不了,可嘗試發(fā)送這個(gè)信號。

  • SIGSEGV
    試圖訪問未分配給自己的內(nèi)存, 或試圖往沒有寫權(quán)限的內(nèi)存地址寫數(shù)據(jù).

  • SIGPIPE
    管道破裂。這個(gè)信號通常在進(jìn)程間通信產(chǎn)生,比如采用FIFO(管道)通信的兩個(gè)進(jìn)程,讀管道沒打開或者意外終止就往管道寫,寫進(jìn)程會(huì)收到SIGPIPE信號。

  • SIGSYS

    非法的系統(tǒng)調(diào)用。

  • SIGTRAP

    由斷點(diǎn)指令或其它 trap 指令產(chǎn)生. 由d ebugger 使用。

  • SIGILL

    執(zhí)行了非法指令. 通常是因?yàn)榭蓤?zhí)行文件本身出現(xiàn)錯(cuò)誤, 或者試圖執(zhí)行數(shù)據(jù)段. 堆棧溢出時(shí)也有可能產(chǎn)生這個(gè)信號。

3)應(yīng)用級NSException

應(yīng)用級異常,它是未被捕獲的Objective-C異常,導(dǎo)致程序向自身發(fā)送了SIGABRT信號而崩潰,是app自己可控的,對于未捕獲的Objective-C異常,是可以通過try catch來捕獲的,或者通過NSSetUncaughtExceptionHandler()機(jī)制來捕獲。

  • 非主線程刷新UI

  • NSInvalidArgumentException
    非法參數(shù)異常(NSInvalidArgumentException)是 Objective – C 代碼最常出現(xiàn)的錯(cuò)誤,所以平時(shí)在寫代碼的時(shí)候,需要多加注意,加強(qiáng)對參數(shù)的檢查,避免傳入非法參數(shù)導(dǎo)致異常,其中尤以nil參數(shù)為甚。

  • NSRangeException
    越界異常(NSRangeException)也是比較常出現(xiàn)的異常。

  • NSGenericException
    NSGenericException這個(gè)異常最容易出現(xiàn)在foreach操作中,在for in循環(huán)中如果修改所遍歷的數(shù)組,無論你是add或remove,都會(huì)出錯(cuò) “for in”,它的內(nèi)部遍歷使用了類似 Iterator進(jìn)行迭代遍歷,一旦元素變動(dòng),之前的元素全部被失效,所以在foreach的循環(huán)當(dāng)中,最好不要去進(jìn)行元素的修改動(dòng)作,若需要修改,循環(huán)改為for遍歷,由于內(nèi)部機(jī)制不同,不會(huì)產(chǎn)生修改后結(jié)果失效的問題。

  • NSInternalInconsistencyException
    不一致導(dǎo)致出現(xiàn)的異常
    比如NSDictionary當(dāng)做NSMutableDictionary來使用,從他們內(nèi)部的機(jī)理來說,就會(huì)產(chǎn)生一些錯(cuò)誤
    NSMutableDictionary *info = method return to NSDictionary type;
    [info setObject:@“sxm” forKey:@”name”];
    比如xib界面使用或者約束設(shè)置不當(dāng)

  • NSFileHandleOperationException
    處理文件時(shí)的一些異常,最常見的還是存儲(chǔ)空間不足的問題,比如應(yīng)用頻繁的保存文檔,緩存資料或者處理比較大的數(shù)據(jù):
    所以在文件處理里,需要考慮到手機(jī)存儲(chǔ)空間的問題。

  • NSMallocException
    這也是內(nèi)存不足的問題,無法分配足夠的內(nèi)存空間
    此外還有

  • KVO Crash
    移除未注冊的觀察者
    重復(fù)移除觀察者
    添加了觀察者但是沒有實(shí)現(xiàn)-observeValueForKeyPath:ofObject:change:context:方法
    添加移除keypath=nil
    添加移除observer=nil

  • unrecognized selector send to instance

總結(jié)

本文也只是對崩潰問題做了淺顯的總結(jié)和解決經(jīng)驗(yàn)的分享,崩潰治理是開發(fā)者長期處理的過程,不僅要解決現(xiàn)有問題,還要防范崩潰問題出現(xiàn)并且做好兜底策略;在治理過程中對個(gè)人底層知識(shí)理解也有較大幫助。

參考:

https://juejin.cn/post/6937619147505270820

http://m.itdecent.cn/p/3f6775c02257

https://www.cnblogs.com/ciml/p/7422872.html

https://zhuanlan.zhihu.com/p/420032439

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容