了解和分析應用崩潰報告

當一個應用崩潰時,會產生一個崩潰報告。這個報告對分析崩潰問題是非常有用的。這篇文章主要講述了如何符號化、了解和分析應用報告。

1. 簡介

當一個應用崩潰時,會隨之產生一個崩潰報告存儲在設備上。崩潰報告描述了當時的崩潰情況,在絕大多數時候包含每個線程的堆?;厮?。你可以通過分析這些報告來了解應用的崩潰并且修復它們。

在分析一個報告之前,你需要先符號化它。符號化就是把原始的地址信息轉換為刻度的函數名和對應的行數。如果你通過Xcode的devices窗口獲得一個設備的崩潰日志,它會自動被符號化。

低內存報告與其他報告是不同的,它沒有堆?;厮菪畔ⅰ.斢捎诘蛢却嬉l崩潰后,你必須研究一下你的內存使用方式和對內存警告的處理。

2. 符號化崩潰報告

符號化是一種把堆棧地址轉換為源碼匯總函數名的過程。一個沒有符號化的崩潰報告是無法分析出崩潰如何發生的。

注意:低內存報告不需要符號化。

tn2151_crash_flow.png

1.隨著編譯器把源碼轉換為機器碼,它同時產生了一堆debug符號,這寫符號記錄著源碼和機器碼之間的對應關系。根據Build Settings中的Debug Infomartion Format,這些符號會被存入一個二進制文件中或者DSYM中。默認的選項是存入DSYM文件中,這樣會使文件的體積更小。

Debug符號文件通過UUID來和應用的二進制文件建立聯系。每次build一個應用,都會產生一個新的UUID。即使源碼一模一樣,編譯器設置也一樣,build之后的UUID都是不同的。

2.當你archive一個應用準備發布時,Xcode會把應用的二進制文件和DYSM文件放在同一個目錄下。

注意:為了能夠符號化來自tester,App review和用戶的崩潰報告,你必須保留每次發布的archive。

3.如果你通過App Store發布應用,或者通過Test Flight發布測試版本應用,你都將會收到一個選擇是否上傳DYSM文件的選擇。對于TestFlight用戶上傳的崩潰報告,必須要上傳DSYM文件。

注意:來自App review的崩潰報告不會被符號化,即使你上傳了DSYM文件。你需要使用Xcode來符號化崩潰報告。

4.當你的應用崩潰了,一個沒有符號化的崩潰報告會被存儲在設備上。

5.取回用戶的崩潰報告,一是可以通過Xcode直接獲得設備的報告,二是用戶的手機設置了允許上傳診斷數據。

6.通過設備取回的崩潰報告是沒有符號化的,需要通過Xcode來使用DSYM文件符號化它。

7.如果用戶開啟了與apple共享數據的選項,或者用戶通過TestFlight安裝了beta版應用,崩潰報告會上傳到App Store。

8.App Store會符號化收到的崩潰報告。

9.可以通過Xcode的Crashes organizer來讀取符號化的崩潰報告。

2.1 Bitcode

BitCode是編譯后的程序的一種中間呈現代碼。當你在bitcode選項打開時archive一個應用,編譯器會產生包含bitcode的二進制,而不是機器碼。一旦這個二進制被上傳到App Store,bitcode會被編譯成機器碼。這樣的話,如果編譯器性能提高了就不需要再次編譯二進制,而是通過App Store直接再次編譯bitcode。


tn2151_bitcode_overview.png

由于最終的編譯時在App Store完成的,因此你的Mac電腦上存儲的DSYM文件不能夠符號化來自App review或者用戶的崩潰報告。App Store在把bitcode轉換為機器碼時會產生一個DYSM文件,你可以通過Xcode或者iTunes Connect網站下載。你必須使用這個DYSM文件來符號化上述的崩潰報告。而通過崩潰報告服務上傳的崩潰報告會被App Store自動符號化。

注意:原始提交的二進制映像的UUID和被App Store編譯后的二進制映像的UUID是不同的。

通過Xcode下載DSYM文件
  1. 在Archives organizer中,選擇提交到App Store的archive。
  2. 點擊下載DSYMs按鈕。
通過iTunes Connect網站下載DSYM
  1. 打開App詳情頁面。
  2. 點擊Activity。
  3. 從一系列builds中選擇一個版本。
  4. 點擊下載DSYM鏈接。
轉換隱藏符號名到原始符號名

當你上傳帶有bitcode的應用到App Store去時,你可以不勾選彈窗中的"Upload your app's symbols to receive symbolicated reports from Apple" 選項。如果你不勾選,Xcode會混淆.dSYM文件,再上傳到iTunes Connect上。Xcode會在原始符號和隱藏符號之間建立一個mapping,然后把這個mapping存入.bcsymbolmap文件中,這個文件會包含在archive中。

在符號化崩潰報告時,你需要解密從iTunes Connect下載的.dSYM文件。如果你是從Xcode下載的.dSYM文件,Xcode會自動解密。從iTunes Connect下載的.dSYM文件可以通過如下命令行解密:

xcrun dsymutil -symbol-map ~/Library/Developer/Xcode/Archives/2017-11-23/MyGreatApp\ 11-23-17\,\ 12.00\ PM.xcarchive/BCSymbolMaps ~/Downloads/dSYMs/3B15C133-88AA-35B0-B8BA-84AF76826CE0.dSYM
2.2 是否符號化一個崩潰報告

一個崩潰報告可能是沒被符號化的,或者全部符號化的。或者部分符號化的。沒有符號化的崩潰報告不會在回溯信息中包含方法或者函數名。你得到的是16進制的地址。完全符號化的崩潰報告,每一行16進制地址都被轉換為響應的符號。部分符號化的崩潰報告,只有部分地址被符號化。

對于分析崩潰報告,明顯是需要一個完全符號化的報告。


tn2151_symbolication_levels.png
2.3 通過Xcode來符號化崩潰報告

Xcode會嘗試自動符號化一個崩潰報告。你需要做的只是把崩潰報告放入Xcode Organizer中。

注意:Xcode不會解析不以.crash為后綴的文件。如果你收到一個不正確后綴的報告,把后綴為.crash。

  1. 連接iOS設備到Mac
  2. 從Window菜單中選擇Devices
  3. 在左邊的DEVICES列表中選擇一個device
  4. 在右邊的界面中點擊 "View Device Logs" 按鈕
  5. 把崩潰報告拖入
  6. Xcode自動符號化并展現結果

為了能夠符號化崩潰報告,Xcode需要定位到以下幾個內容:

  • 崩潰應用的二進制映像和dSYM文件
  • 應用鏈接的通用framework的二進制映像和dSYM需再次鏈接。對于源碼打包的framework,其對應的dSYM文件會隨著應用一同放入。對于第三方的framework,你需要問作者拿取dSYM。
  • 應用崩潰時的操作系統符號。這些符號包含操作系統中framework的debug信息。Xcode會自動從設備拷貝操作系統的符號到Mac上。

如果缺少以上的任何一個信息,都將不能符號化崩潰報告,或者僅能部分符號化崩潰報告。

2.4 通過atos符號化崩潰報告

atos命令可以把地址轉換為相應的符號。如果全部的debug符號信息都是可用的,那么atos的輸出將包含文件名和行數信息。使用atos來符號化部分日志報告:

  1. 找到你想符號化的堆棧信息中某一行。二進制映像的的名字在第二列,地址是在第三列。

  2. 從崩潰報告中末尾的二進制映像列表中找尋相應的二進制映像。


    tn2151_atos_info.png
  3. 通過UUID定位這個二進制映像的dSYM。

  4. 通過上述信息你能通過atos命令符號化相應的地址信息。

     atos -arch <Binary Architecture> -o <Path to dSYM file>/Contents/Resources/DWARF/<binary image name> -l <load address> <address to symbolicate>
    
3. 分析崩潰報告
3.1 Header

每個崩潰報告都有一個header。

Incident Identifier: B6FD1E8E-B39F-430B-ADDE-FC3A45ED368C
CrashReporter Key: f04e68ec62d3c66057628c9ba9839e30d55937dc
Hardware Model: iPad6,8
Process: TheElements [303]
Path: /private/var/containers/Bundle/Application/888C1FA2-3666-4AE2-9E8E-62E2F787DEC1/TheElements.app/TheElements
Identifier: com.example.apple-samplecode.TheElements
Version: 1.12
Code Type: ARM-64 (Native)
Role: Foreground
Parent Process: launchd [1]
Coalition: com.example.apple-samplecode.TheElements [402]

Date/Time: 2016-08-22 10:43:07.5806 -0700
Launch Time: 2016-08-22 10:43:01.0293 -0700
OS Version: iPhone OS 10.0 (14A5345a)
Report Version: 104
  • Incident Identifier:報告的唯一標識符。不同的報告的標識符不同。
  • CrashReporter Key:設備隱秘的identifier。同一設備不同的報告的值相同。
3.2 異常信息

崩潰可以有很多Mach異常類型導致。不是所有的異常類型都會在崩潰報告中。

由于uncaught Objective-C exception引起的崩潰

Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Triggered by Thread: 0

由于空指針引起的崩潰

Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000
Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [0]
Triggered by Thread: 0
  • Exception Codes: 程序設置的關于異常的信息。這個信息是編碼成16進制。一般,日志報告會解析這個信息成可讀的描述,放入其它字段中。
  • Exception Subtype:可讀的exception code的名字。
  • Exception Message:解析過后的exception code。
  • Exception Note:沒有被設置成異常類型的額外信息。如果這個字段包含SIMULATED,意味著這個程序沒有崩潰,而是被系統殺死,比如watchdog。
  • Exception Reason:崩潰原因。
  • Triggered by Thread: 崩潰的線程。

接下去來介紹一下常見的異常類型:

Bad Memory Access [EXC_BAD_ACCESS // SIGSEGV // SIGBUS]
程序嘗試進入無效的內存,或者嘗試進入不被允許進入的內存。Exception Subtype字段包含kern_return_t用來描述錯誤和錯誤進入的內存地址。

下面是一些錯誤內存進入崩潰的調試技巧:

  • 如果objc_msgSend或者objc_release在崩潰線程堆?;厮莸捻敳扛浇?,程序可能嘗試向一個釋放的對象發送消息。你應該設置Zombies instrument來進一步分析崩潰的狀況。
  • 如果gpus_ReturnNotPermittedKillClient在崩潰線程堆?;厮莸捻敳扛浇绦蚩赡苁怯捎谟肙penGL ES或者Metal在后臺進行渲染。
  • 設置 Address Sanitizer來運行你的程序。

Abnormal Exit [EXC_CRASH // SIGABRT]
程序非正常退出。這種崩潰絕大多數由于uncaught Objective-C/C++異常和調用abort()引起。

Trace Trap [EXC_BREAKPOINT // SIGTRAP]
跟非正常退出類型。這個異常會打算給一個附加的調試器,使有機會在設定的點來中止程序。你能通過__builtin_trap()函數來觸發這個異常。如果沒有調試器被附加,程序會終止并產生崩潰報告。
底層庫在遇到致命錯誤后會觸發這個異常。關于這個錯誤的詳細信息可以在下面的Additional Diagnostic Information中找到。
swifi代碼在runtime時如果如下幾種情況時也會產生這種異常:

  • 非可選類型被賦予nil
  • 強制進行錯誤的類型轉換

Illegal Instruction [EXC_BAD_INSTRUCTION // SIGILL]
程序嘗試執行一個非法的或者沒有定義的指令。程序可能通過一個錯誤的函數指針進入一個無效的地址。

Quit [SIGQUIT]
程序被其他程序終止。在iOS中,鍵盤extension可能被宿主app殺死由于加載時間太長。

Killed [SIGKILL]
程序被系統終止。

Guarded Resource Violation [EXC_GUARD]
程序違反進入保護的資源。比如程序使用SQLite命令來操作Core Data,將會導致崩潰。

Resource Limit [EXC_RESOURCE]
程序超過了資源消耗的限制。

Other Exception Types
一些崩潰報告可能報告沒有命名的異常類型,只會打印16進制數值。

  • 0xbaaaaaad表示日志是整個系統的一個堆棧快照(stackshot)而不是一個崩潰報告。通過按下Home鍵和任意音量鍵可以獲得堆??煺眨╯tackshot)。通常這些日志是被用戶意外創建的(不小心同時按下了Home鍵+音量鍵),而不是一個錯誤。
  • 0xbad22222表示一個VoIP應用由于恢復過于頻繁而被iOS結束進程。
  • 0x8badf00d表示一個應用由于watchdog發生超時而被iOS結束進程。這表明該應用程序在啟動、結束或者響應系統事件時花費太長時間。一個常見的例子是在主線程上實現同步的網絡操作。任何在Thread 0(主線程)上的操作都應該放到后臺線程上執行,或者使用不阻塞主線程的方式進行處理。
  • 0xc00010ff表示一個應用由于響應一個熱事件(thermal event)而被操作系統殺掉進程。這可能是由于在特定的設備上發生崩潰,或者是操作環境的問題。為了讓你的程序獲得更多有效的提示,請觀看使用Instruments來提升iOS性能和電量優化的WWDC會議
  • 0xdead10cc表示一個應用由于在后臺運行時還保留著系統的資源(如通訊錄數據庫)而被iOS結束進程。
  • 0x2bad45ec表示應用程序違反安全規則被強制退出。"Process detected doing insecure drawing while in secure mode"表示應用嘗試draw在不被允許的時候,比如屏幕上鎖時。用戶可能不會注意到這個終止因為屏幕是被上鎖了。

注意:終止一個掛起的程序不會產生崩潰報告。

3.2 額外的診斷信息 (Additional Diagnostic Information)
  • Application Specific Information:在程序終止前被捕獲到的framework錯誤信息
  • Kernel Messages:代碼簽名問題詳情
  • Dyld Error Messages:動態鏈接器發出的錯誤信息

鏈接的framework無法被找到引起的崩潰

Dyld Error Message:
Dyld Message: Library not loaded: @rpath/MyCustomFramework.framework/MyCustomFramework
  Referenced from: /private/var/containers/Bundle/Application/CD9DB546-A449-41A4-A08B-87E57EE11354/TheElements.app/TheElements
  Reason: no suitable image found.

加載初始化view controller失敗引起的崩潰

Application Specific Information:
com.example.apple-samplecode.TheElements failed to scene-create after 19.81s (launch took 0.19s of total time limit 20.00s)

Elapsed total CPU time (seconds): 7.690 (user 7.690, system 0.000), 19% CPU
Elapsed application CPU time (seconds): 0.697, 2% CPU
3.4 回溯

崩潰日志中最有趣的部分是程序終止時的每個線程回溯。

Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   TheElements                     0x000000010006bc20 -[AtomicElementViewController myTransitionDidStop:finished:context:] (AtomicElementViewController.m:203)
1   UIKit                           0x0000000194cef0f0 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 312
2   UIKit                           0x0000000194ceef30 -[UIViewAnimationState animationDidStop:finished:] + 160
3   QuartzCore                      0x0000000192178404 CA::Layer::run_animation_callbacks(void*) + 260
4   libdispatch.dylib               0x000000018dd6d1c0 _dispatch_client_callout + 16
5   libdispatch.dylib               0x000000018dd71d6c _dispatch_main_queue_callback_4CF + 1000
6   CoreFoundation                  0x000000018ee91f2c __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
7   CoreFoundation                  0x000000018ee8fb18 __CFRunLoopRun + 1660
8   CoreFoundation                  0x000000018edbe048 CFRunLoopRunSpecific + 444
9   GraphicsServices                0x000000019083f198 GSEventRunModal + 180
10  UIKit                           0x0000000194d21bd0 -[UIApplication _run] + 684
11  UIKit                           0x0000000194d1c908 UIApplicationMain + 208
12  TheElements                     0x00000001000653c0 main (main.m:55)
13  libdyld.dylib                   0x000000018dda05b8 start + 4

Thread 1:
0   libsystem_kernel.dylib          0x000000018deb2a88 __workq_kernreturn + 8
1   libsystem_pthread.dylib         0x000000018df75188 _pthread_wqthread + 968
2   libsystem_pthread.dylib         0x000000018df74db4 start_wqthread + 4

...

第一行列舉了線程的序號和當前隊列的標識。剩下的行表示回溯中的堆棧詳情。從左到右依次為:

  • 堆序號
  • 執行這個函數的二進制映象名稱
  • 機器指令地址
  • 符號化的方法名
異常(Exceptions)

Objective-C中的異常是用來指明程序運行時檢測到的錯誤的,比如數組越界,轉換不可變對象為可變對象,沒有實現一個必要的方法或者協議,或者給接收者發送一個無法識別的message。

注意:給已經釋放的對象發送消息可能會引發NSInvalidArgumentException,而不是違反內存進入崩潰。發生這種情況常常是被創建的新對象的內存覆蓋了先前已經釋放對象的內存。如果你的程序由于沒有捕獲NSInvalidArgumentException引起崩潰,可以使用 Zombies instrument來解決引發這種錯誤內存管理的問題。

如果一個異常沒有被捕獲,它會被一個叫做uncaught exception handler的函數攔截。uncaught exception handler默認在設備的console打印異常信息,然后終止程序。這是崩潰報告中只會在Last Exception Backtrace節中有這個異常的回溯。詳細的異常信息在崩潰報告中被遺漏。如果你收到一個含有Last Exception Backtrace的崩潰報告,你應該從原始射中中獲取console日志來更好的了解當時引起異常的情況。

Last Exception Backtrace:
(0x18eee41c0 0x18d91c55c 0x18eee3e88 0x18f8ea1a0 0x195013fe4 0x1951acf20 0x18ee03dc4 0x1951ab8f4 0x195458128 0x19545fa20 0x19545fc7c 0x19545ff70 0x194de4594 0x194e94e8c 0x194f47d8c 0x194f39b40 0x194ca92ac 0x18ee917dc 0x18ee8f40c 0x18ee8f89c 0x18edbe048 0x19083f198 0x194d21bd0 0x194d1c908 0x1000ad45c 0x18dda05b8

一個含有Last Exception Backtrace的崩潰報告只會有16進制地址,它必須被符號化才能變得可讀。

下面是符號化的日志報告中的Last Exception Backtrace節異常。這個異常是由于缺少IBOutlet在storyboard中引起的。

Last Exception Backtrace:
0   CoreFoundation                  0x18eee41c0 __exceptionPreprocess + 124
1   libobjc.A.dylib                 0x18d91c55c objc_exception_throw + 56
2   CoreFoundation                  0x18eee3e88 -[NSException raise] + 12
3   Foundation                      0x18f8ea1a0 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 272
4   UIKit                           0x195013fe4 -[UIViewController setValue:forKey:] + 104
5   UIKit                           0x1951acf20 -[UIRuntimeOutletConnection connect] + 124
6   CoreFoundation                  0x18ee03dc4 -[NSArray makeObjectsPerformSelector:] + 232
7   UIKit                           0x1951ab8f4 -[UINib instantiateWithOwner:options:] + 1756
8   UIKit                           0x195458128 -[UIStoryboard instantiateViewControllerWithIdentifier:] + 196
9   UIKit                           0x19545fa20 -[UIStoryboardSegueTemplate instantiateOrFindDestinationViewControllerWithSender:] + 92
10  UIKit                           0x19545fc7c -[UIStoryboardSegueTemplate _perform:] + 56
11  UIKit                           0x19545ff70 -[UIStoryboardSegueTemplate perform:] + 160
12  UIKit                           0x194de4594 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1352
13  UIKit                           0x194e94e8c -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 268
14  UIKit                           0x194f47d8c _runAfterCACommitDeferredBlocks + 292
15  UIKit                           0x194f39b40 _cleanUpAfterCAFlushAndRunDeferredBlocks + 560
16  UIKit                           0x194ca92ac _afterCACommitHandler + 168
17  CoreFoundation                  0x18ee917dc __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32
18  CoreFoundation                  0x18ee8f40c __CFRunLoopDoObservers + 372
19  CoreFoundation                  0x18ee8f89c __CFRunLoopRun + 1024
20  CoreFoundation                  0x18edbe048 CFRunLoopRunSpecific + 444
21  GraphicsServices                0x19083f198 GSEventRunModal + 180
22  UIKit                           0x194d21bd0 -[UIApplication _run] + 684
23  UIKit                           0x194d1c908 UIApplicationMain + 208
24  TheElements                     0x1000ad45c main (main.m:55)
25  libdyld.dylib                   0x18dda05b8 start + 4

注意:如果你發現應用程序所指定的異常處理域的異常在拋出時沒有被捕獲,請檢查你的應用在編譯時是否設置了-no_compact_unwind標識。

64位的iOS系統使用了“零成本”異常實現。在“零成本”系統中,每個函數都有額外的數據來描述如何展開堆棧,在異常拋出時。如果拋出了一個沒有展開數據的堆棧的異常,異常就無法被處理,然后程序被終止。異常處理程序可能能處理堆棧,但是如果沒有展開數據的堆棧,那么就沒有辦法從異常中獲取相應的堆棧。設置-no_compact_unwind標識意味著你不需要展開的數據,那么你就不能從那些函數中拋出異常。

此外,如果你的程序或者庫中包含C代碼,你需要指定-funwind-tables標識來讓你的代碼中的函數包含展開數據。

3.5 線程狀態

這一節主要列舉崩潰線程的線程狀態。下面是程序終止時寄存器的值。在閱讀崩潰報告時,不一定要了解線程狀態,但是如果能夠使用這些信息的話,就會更好的了解當時的崩潰狀態。

Thread 0 crashed with ARM Thread State (64-bit):
    x0: 0x0000000000000000   x1: 0x000000019ff776c8   x2: 0x0000000000000000   x3: 0x000000019ff776c8
    x4: 0x0000000000000000   x5: 0x0000000000000001   x6: 0x0000000000000000   x7: 0x00000000000000d0
    x8: 0x0000000100023920   x9: 0x0000000000000000  x10: 0x000000019ff7dff0  x11: 0x0000000c0000000f
   x12: 0x000000013e63b4d0  x13: 0x000001a19ff75009  x14: 0x0000000000000000  x15: 0x0000000000000000
   x16: 0x0000000187b3f1b9  x17: 0x0000000181ed488c  x18: 0x0000000000000000  x19: 0x000000013e544780
   x20: 0x000000013fa49560  x21: 0x0000000000000001  x22: 0x000000013fc05f90  x23: 0x000000010001e069
   x24: 0x0000000000000000  x25: 0x000000019ff776c8  x26: 0xee009ec07c8c24c7  x27: 0x0000000000000020
   x28: 0x0000000000000000  fp: 0x000000016fdf29e0   lr: 0x0000000100017cf8
    sp: 0x000000016fdf2980   pc: 0x0000000100017d14 cpsr: 0x60000000
3.6 二進制映象

這一節列舉了程序終止時加載的二進制映象。

Binary Images:
0x100060000 - 0x100073fff TheElements arm64 <2defdbea0c873a52afa458cf14cd169e> /var/containers/Bundle/Application/888C1FA2-3666-4AE2-9E8E-62E2F787DEC1/TheElements.app/TheElements
...

每一行列出二進制映象的一下細節:

  • 二進制映象在進程中地址
  • 二進制映象的名字或者包名(macOS only)
  • 二進制映象的版本信息(macOS only)
  • 二進制映象的架構(iOS only)
  • 二進制映象的UUID
  • 二進制映象在磁盤上的路徑
4. 了解低內存報告

當低內存被檢測到時,iOS上的虛擬內存系統會協調應用來釋放內存。低內存通知被發送到所有正在運行的應用來處理釋放內存的請求,希望來降低使用的內存的總量。如果內存壓力依舊存在,系統可能終止在后臺的程序來降低內存壓力。如果足夠的內存被釋放掉,你的程序將繼續運行。如果沒有的話,你的程序將會被終止,因為沒有足夠的內存來滿足程序的需求,同時會在設備上生成一個低內存報告。

低內存報告的形式于其他崩潰報告不同,它沒有程序線程的回溯信息。低內存報告的header和崩潰報告的相同。需要注意page size這個字段。每個程序的內存使用都會在低內存報告中內存頁數量的形式展示。

低內存報告中最重要的時程序表。程序表包含所有正在運行的程序,包括系統守護進程。如果一個程序被殺死,原因會在 [reason]列中展示。一個程序可能被殺死的原因有以下這么幾個:

  • per-process-limit: 該進程跨越了系統施加的內存限制。系統為所有應用建立的常駐內存進行了限制。跨越該限制的進程將會被終止。
  • vm-pageshortage/vm-thrashing/vm: 由于內存壓力被殺死
  • vnode-limit: 太多的文件被打開
  • highwater: 系統守護進程到達了它的內存使用限制
  • jettisoned: 其他原因

如果你沒有看到原因中列出你的應用/擴展的進程,那么可能不是因為內存壓力引起的崩潰。查看.crash文件(上一節講述的)了解更多信息。

當你看到一個低內存崩潰時,與其關心那一部分代碼在應用終止時正在執行,倒不如檢查你對內存的使用方式和對低內存警告的響應處理。在你的應用中查找內存問題一文中詳細地講述了如何使用Instruments的Leaks分析來發現內存泄露,以及如何使用Allocations分析的Mark Heap功能來防止出現被遺棄的內存。《內存使用性能指南》論述了一種正確的方法來應對低內存通知,同時又提供了很多有效使用內存的技巧。同時也建議你看看WWDC2010年會議,使用Instruments進行高級內存分析。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容