簡單地認識iOS Crash Report

Crash Reports的種類

一、跟iOS有關的:基本上這類Crash就是違反iOS規範而被終止的。

1. Watchdog timeout

透過一個timer去觀察某個事件(通常是網路存取)是否已經超過預期的時間,如果是的話就發出中斷告訴OS結束此程式(Your application failed to Launch/Resume/Suspend/Quit in a given timeframe),最主要的原因都是因為synchronous http request導致整個畫面動彈不得,毫無反應。

  • Exception code: 0x8badf00d
  • Don’t block main thread
  • Use API for asynchronous URL request

2. User force-quit

使用者會強制結束程式的執行可能就是因為程式在某些情境下沒有反應,所以這種狀況也會被視為crash而寫入crash report。

  • Exception Type: 00000020
  • Exception Codes: 0xdeadfa11

3. Low memory termination

由字面上的意思可以很輕易瞭解這就是因為可用記憶體不足而導致程式被終止,iOS的記憶體管理也是一門學問,會再另闢一篇文章來討論。

這邊簡單提一下該注意的事項:

  1. 一定要注意記憶體不足的通知
  2. 如果物件暫時不會用到並且要用到的時候還可以重新建構的話,用完的時候就順手釋放吧!
  3. 釋放事前快取起來的物件

最上面(Front-most)的通常就是目前運行中的程序,如果os收到記憶體不足的警告它會先去砍背景執行的程式,如果還是不夠,那就會去砍front-most的程式(通常就是active的)
大家應該可以發現SpringBoard也是Active,這是因為它是負責與使用者之間互動的程序,並且大部分時間都會是Active的。

Current resident pages:當掉瞬間所佔用的page數
Count: 該行程所佔用的頁數(pages)
UUID: Universally Unique IDentifier
jettisoned:因為記憶體不足而被從記憶體移出
active: 運行中

如果記憶體管理的不好,可能就會造成Memory Leak,這時候我們可以善用XCode上的工具來檢查:

  1. Run -> Run With Performance Tool -> (Instrument) Leak
  2. Build and Analyze

二、程式本身的bug導致:沒有固定的Exception Codes & Type

最常犯的三個錯誤:

  1. Over-released objects
  2. Null pointer dereference
  3. Insert nil object

哪裡可以取得Crash Reports?

依照OS的不同,存放路徑也不盡相同
Mac OS X: ~/Library/Logs/CrashReporter/MobileDevice/
Windows XP: C:\Documents and Settings\Application Data\Apple Computer\Logs\CrashReporter\MobileDevice\
Windows Vista + 7: C:\Users\AppData\Roaming\Apple Computer\Logs\CrashReporter\MobileDevice\

取得用戶的Crash logs: iTunes Connect(如圖)

接下來讓我們來看看實際上的Crash Report到底長得像怎樣?

這是第一部分,主要就是列出當掉的這個應用程式的相關資訊:

Incident Identifier: D3FF4CD1-D6DA-4247-8D86-2A94F937FE49 CrashReporter Key: 5fe15c84f609062a9486b560622502d36e8c467d Hardware Model: iPhone3,1 Process: WishMap [3908] Path: /var/mobile/Applications/ACEC73B2-2D24-40F3-AB47-3B99371B64B4/WishMap.app/WishMap Identifier: WishMap Version: ??? (???) Code Type: ARM (Native) Parent Process: launchd [1]

這部份最重要的就是OS Version,因為很有可能是因為你的程式沒有完美的向下相容才引發Crash:

Date/Time: 2010-09-23 14:51:55.431 +0800 OS Version: iPhone OS 4.1 (8B117) Report Version: 104

看Crash Report必看的部份,可以從這段訊息中得知到底是哪類型的錯誤,由下面這個例子,我們可以很清楚的瞭解到程式是因為收到SIGTRAP的signal而當掉的(這個例子是因為在debug模式強制結束而產生的crash report),而有些特定的Crash都會有其固定的Exception Codes讓你可以初步知道這是哪類型的Crash,最後,明確告訴你此Crash是因為哪個執行緒引發的(iOS is Multithreading),不過要注意的是,這只能參考而已,沒有絕對,因為多執行緒的行為可以是相當複雜的。

Exception Type: EXC_CRASH (SIGTRAP) Exception Codes: 0x00000000, 0x00000000 Crashed Thread: 1

列出所有Thread的backtrace,如果沒有經過Symbolication,那麼最後面就只是base + offset的純十六進位記憶體位址,那要如何做Symbolication呢?只要針對每次不同的版本做一次"Build and Archive",XCode Organizer會自動去掃瞄已經儲存的應用程式版本,自動把那些位址轉成可讀的程式碼片段:

Thread 0: 0 dyld 0x2fe10e9a ImageLoaderMachOCompressed::findClosestSymbol(void const*, void const**) const + 186 1 ??? 0x35a2e6dc 0 + 899868380 2 libSystem.B.dylib 0x0000359e dladdr + 42 3 libSystem.B.dylib 0x000541da backtrace_symbols + 54 4 Foundation 0x0008db38 -[_NSCallStackArray descriptionWithLocale:indent:] + 84 5 CoreFoundation 0x0009544c -[NSArray description] + 12 6 CoreFoundation 0x0009ff9c __handleUncaughtException + 96 7 libobjc.A.dylib 0x00005950 _objc_terminate + 96 8 libstdc++.6.dylib 0x00042df2 __cxxabiv1::__terminate(void ()()) + 46 9 libstdc++.6.dylib 0x00042e46 std::terminate() + 10 10 libstdc++.6.dylib 0x00042f16 __cxa_throw + 78 11 libobjc.A.dylib 0x00004838 objc_exception_throw + 64 12 CoreFoundation 0x00031d72 -[__NSArrayM objectAtIndex:] + 178 13 WishMap 0x00006438 -[WantedMapViewController displayOwnAnnotation] (WantedMapViewController.m:183) 14 WishMap 0x0000624e -[WantedMapViewController startUpdatingLocation:] (WantedMapViewController.m:157) 15 CoreFoundation 0x00047712 -[NSObject(NSObject) performSelector:withObject:withObject:] + 18 16 UIKit 0x0006413a -[UIApplication sendAction:to:from:forEvent:] + 78 17 UIKit 0x000bb30e -[UIBarButtonItem(UIInternal) _sendAction:withEvent:] + 86 18 CoreFoundation 0x00047712 -[NSObject(NSObject) performSelector:withObject:withObject:] + 18 19 UIKit 0x0006413a -[UIApplication sendAction:to:from:forEvent:] + 78 20 UIKit 0x000640da -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 26 21 UIKit 0x000640ac -[UIControl sendAction:to:forEvent:] + 32 22 UIKit 0x00063dfe -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 350 23 UIKit 0x0006444c -[UIControl touchesEnded:withEvent:] + 336 24 UIKit 0x00062dd6 -[UIWindow _sendTouchesForEvent:] + 362 25 UIKit 0x00062750 -[UIWindow sendEvent:] + 256 26 UIKit 0x0005d9f8 -[UIApplication sendEvent:] + 292 27 UIKit 0x0005d330 _UIApplicationHandleEvent + 5104 28 GraphicsServices 0x00005044 PurpleEventCallback + 660 29 CoreFoundation 0x00034cdc CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION + 20 30 CoreFoundation 0x00034ca0 __CFRunLoopDoSource1 + 160 31 CoreFoundation 0x00027566 __CFRunLoopRun + 514 32 CoreFoundation 0x00027270 CFRunLoopRunSpecific + 224 33 CoreFoundation 0x00027178 CFRunLoopRunInMode + 52 34 GraphicsServices 0x000045ec GSEventRunModal + 108 35 GraphicsServices 0x00004698 GSEventRun + 56 36 UIKit 0x0000411c -[UIApplication _run] + 396 37 UIKit 0x00002128 UIApplicationMain + 664 38 WishMap 0x0000304c main (main.m:11) 39 WishMap 0x00002fcc start + 44 Thread 1 Crashed: 0 libSystem.B.dylib 0x0002d330 kevent + 24 1 libSystem.B.dylib 0x000d6b6c _dispatch_mgr_invoke + 88 2 libSystem.B.dylib 0x000d65bc _dispatch_queue_invoke + 96 3 libSystem.B.dylib 0x000d675c _dispatch_worker_thread2 + 120 4 libSystem.B.dylib 0x0007a67a _pthread_wqthread + 258 5 libSystem.B.dylib 0x00073190 start_wqthread + 0 Thread 2: 0 libSystem.B.dylib 0x0007b19c __workq_kernreturn + 8 1 libSystem.B.dylib 0x0007a790 _pthread_wqthread + 536 2 libSystem.B.dylib 0x00073190 start_wqthread + 0 Thread 3: 0 libSystem.B.dylib 0x00000c98 mach_msg_trap + 20 1 libSystem.B.dylib 0x00002d64 mach_msg + 44 2 CoreFoundation 0x00027c38 __CFRunLoopServiceMachPort + 88 3 CoreFoundation 0x000274c2 __CFRunLoopRun + 350 4 CoreFoundation 0x00027270 CFRunLoopRunSpecific + 224 5 CoreFoundation 0x00027178 CFRunLoopRunInMode + 52 6 WebCore 0x000024e2 RunWebThread(void) + 362 7 libSystem.B.dylib 0x0007a27e _pthread_start + 242 8 libSystem.B.dylib 0x0006f2a8 thread_start + 0 Thread 4: 0 libSystem.B.dylib 0x00000c98 mach_msg_trap + 20 1 libSystem.B.dylib 0x00002d64 mach_msg + 44 2 CoreFoundation 0x00027c38 __CFRunLoopServiceMachPort + 88 3 CoreFoundation 0x000274c2 __CFRunLoopRun + 350 4 CoreFoundation 0x00027270 CFRunLoopRunSpecific + 224 5 CoreFoundation 0x00027178 CFRunLoopRunInMode + 52 6 Foundation 0x0002d686 +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:] + 206 7 Foundation 0x0000b222 -[NSThread main] + 38 8 Foundation 0x000042d6 NSThread__main + 966 9 libSystem.B.dylib 0x0007a27e _pthread_start + 242 10 libSystem.B.dylib 0x0006f2a8 thread_start + 0 Thread 5: 0 libSystem.B.dylib 0x00025060 select$DARWIN_EXTSN + 20 1 CoreFoundation 0x0005edfc __CFSocketManager + 540 2 libSystem.B.dylib 0x0007a27e _pthread_start + 242 3 libSystem.B.dylib 0x0006f2a8 thread_start + 0 Thread 6: 0 libSystem.B.dylib 0x0007b19c __workq_kernreturn + 8 1 libSystem.B.dylib 0x0007a790 _pthread_wqthread + 536 2 libSystem.B.dylib 0x00073190 start_wqthread + 0 Thread 7: 0 libSystem.B.dylib 0x00000c98 mach_msg_trap + 20 1 libSystem.B.dylib 0x00002d64 mach_msg + 44 2 CoreFoundation 0x00027c38 __CFRunLoopServiceMachPort + 88 3 CoreFoundation 0x000274c2 __CFRunLoopRun + 350 4 CoreFoundation 0x00027270 CFRunLoopRunSpecific + 224 5 CoreFoundation 0x00027178 CFRunLoopRunInMode + 52 6 MapKit 0x00004512 TileCachePrivate::runCacheThread() + 266 7 MapKit 0x000043fe _runCacheThread(void*) + 2 8 libSystem.B.dylib 0x0007a27e _pthread_start + 242 9 libSystem.B.dylib 0x0006f2a8 thread_start + 0 Thread 8: 0 libSystem.B.dylib 0x0007b19c __workq_kernreturn + 8 1 libSystem.B.dylib 0x0007a790 _pthread_wqthread + 536 2 libSystem.B.dylib 0x00073190 start_wqthread + 0 Thread 9: 0 libSystem.B.dylib 0x000791d4 __semwait_signal + 24 1 libSystem.B.dylib 0x0002e1a2 _pthread_cond_wait + 742 2 libSystem.B.dylib 0x0002dd8e pthread_cond_wait + 26 3 QuartzCore 0x000363e0 CA::DispatchGroup::thread(void*) + 76 4 QuartzCore 0x000021a2 thread_fun + 10 5 libSystem.B.dylib 0x0007a27e _pthread_start + 242 6 libSystem.B.dylib 0x0006f2a8 thread_start + 0 Thread 10: 0 libSystem.B.dylib 0x00000c98 mach_msg_trap + 20 1 libSystem.B.dylib 0x00002d64 mach_msg + 44 2 CoreFoundation 0x00027c38 __CFRunLoopServiceMachPort + 88 3 CoreFoundation 0x000274c2 __CFRunLoopRun + 350 4 CoreFoundation 0x00027270 CFRunLoopRunSpecific + 224 5 CoreFoundation 0x00027178 CFRunLoopRunInMode + 52 6 MapKit 0x0000d146 +[NSThread(MKAdditions) _mapkit_runThread:] + 334 7 Foundation 0x0000b222 -[NSThread main] + 38 8 Foundation 0x000042d6 NSThread__main + 966 9 libSystem.B.dylib 0x0007a27e _pthread_start + 242 10 libSystem.B.dylib 0x0006f2a8 thread_start + 0

列出當掉瞬間所有暫存器值:

Thread 1 crashed with ARM Thread State: r0: 0x00000004 r1: 0x00000000 r2: 0x00000000 r3: 0x00580f50 r4: 0x00000001 r5: 0x00580f6c r6: 0x00000000 r7: 0x00580f84 r8: 0x3e08d71c r9: 0x00000000 r10: 0x00000000 r11: 0x00000000 ip: 0x0000016b sp: 0x00580e40 lr: 0x302d5b74 pc: 0x3022c330 cpsr: 0x60000010

最不重要的部份,把程式所使用到的資源(e.g., 圖片、影音、函式庫)訊息列出來:

Binary Images: 0x1000 - 0x15bfff +WishMap armv7 /var/mobile/Applications/ACEC73B2-2D24-40F3-AB47-3B99371B64B4/WishMap.app/WishMap 0x2fc000 - 0x2fdfff dns.so armv7 <240b8d3f07b4fcb234de598f8e67de1a> /usr/lib/info/dns.so 0x2fe00000 - 0x2fe26fff dyld armv7 /usr/lib/dyld 0x3002b000 - 0x300ebfff libobjc.A.dylib armv7 <49029949741e10f21b178b0a4b2df979> /usr/lib/libobjc.A.dylib (下略)

Reference:
http://developer.apple.com/library/ios/#technotes/tn2008/tn2151.html
http://developer.apple.com/library/mac/#technotes/tn2004/tn2123.html