iOS 開發常見崩潰分析

iOS 開發常見崩潰分析

  1. abort(): 函數首先解除進程對SIGABRT信號的阻止,然後向調用進程發送該信號。abort()函數會導致進程的異常終止除非SIGABRT信號被捕捉並且信號處理句柄沒有返回

  2. CorruptMalloc: 堆內存腐化,也就是說默認分配的內存地址很小,但是使用時卻超過我們分配的空間(默認一般是不會崩潰的,但是超過一定數量的話就會造成崩潰,一般超過一個 PAGE_SIZE 大小就會崩潰),Xcode 一般提示如下錯誤: EXC_BAD_ACCESS (code=EXC_I386_GPFLT), 大牛解釋:(Basically, the memory allocator allocates pages of memory at once for use by programs, and it gives you a pointer within them (making sure the following space is free for use). Since these pages are usually bigger than 8KiB, you have no issue in your mini-program. But if a larger program is allocating larger amounts of memory and writing further and further past the end of your allocated space, then you’ll end up attempting to write into unallocated memory (or memory used by another program!), thus corrupting memory.)

  3. userCorruptObject : 非法對象使用,(__bridge id)將一個 C 指針轉換 OC 對象時容易出現,音視頻領域常見該問題。

    注:code=1, address=0x7fff0dd3fc70
    * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x7fff0dd3fc70)
    frame #0: 0x0000000105b63997  libobjc.A.dylib`objc_msgSend + 23
    
    Demo:
        // Random data
    void* pointers[] = {NULL, NULL, NULL};
    void* randomData[] = {
        (void*)"a",
        (void*)"b",
        (void*)pointers,
        (void*)"d",
        (void*)"e",
        (void*)"f"};
    
    // A corrupted/under-retained/re-used piece of memory
    struct {void* isa;} corruptObj = {randomData};
    
    // Message an invalid/corrupt object.
    // This will deadlock if called in a crash handler.
    [(__bridge id)&corruptObj class];
    
  4. C++ execetion: C++ 語言拋出了的異常信息,

     libc++abi.dylib: terminating with uncaught exception of type MyException:
  5. dereferenceBadPointer: 壞指針引用(無效指針引用)

    注:錯誤指針: address=0xffffffffffffffff
    
    * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0xffffffffffffffff)
    * frame #0: 0x000000010fc5739b Crash-Tester`::-[Crasher dereferenceBadPointer](self=0x0000604000005160, _cmd="dereferenceBadPointer") at Crasher.mm:95
    
    
    char* ptr = (char*)-1;
    *ptr = 1;
  6. dereferenceNullPointer: 引用空指針

    注:空指針 address=0x0
    
    * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
    * frame #0: 0x00000001000e13b3 Crash-Tester`::-[Crasher dereferenceNullPointer](self=0x0000600000208730, _cmd="dereferenceNullPointer") at Crasher.mm:100
    
    int* g_crasher_null_ptr = NULL;
    *g_crasher_null_ptr = 1;
  7. stackOverflow : 堆益處崩潰

    
    注: address=0x7ffeed45fff8,code=2
    
    * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x7ffeed45fff8)
    * frame #0: 0x0000000101fa15b8 Crash-Tester`::-[Crasher causeStackOverflow](self=<unavailable>, _cmd=<unavailable>) at Crasher.mm:136
    
    - (void) causeStackOverflow
    {
        [self causeStackOverflow];
    }
  8. Div0:除以 0 崩潰

    * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_ARITHMETIC (code=EXC_I386_DIV, subcode=0x0)
    * frame #0: 0x000000010e50f63e Crash-Tester`::-[Crasher doDiv0](self=0x0000600000006240, _cmd="doDiv0") at Crasher.mm:149
  9. IllegalInstruction: 非法指令,無效數據轉換成函數

     注: address=0x7ffee57c0bb0,code=2
    * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x7ffee57c0bb0)
    frame #0: 0x00007ffee57c0bb0
    
    - (void) doIllegalInstruction
    {
        unsigned int data[] = {0x11111111, 0x11111111};
        void (*funcptr)() = (void (*)())data;
        funcptr();
    }
  10. accessDeallocatedObject: 獲取已經釋放的對象

    
    注:code=EXC_I386_GPFLT
    
    * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
    frame #0: 0x0000000111e4fc9a libobjc.A.dylib`objc_retain + 10
    
    @property(nonatomic, readwrite, assign) id ref;
    
    RefHolder* ref = [RefHolder new];
    ref.ref = [NSArray arrayWithObjects:@"test1", @"test2", nil];
    
    dispatch_async(dispatch_get_main_queue(), ^
    {
       NSLog(@"Object = %@", [ref.ref objectAtIndex:1]);
    });
  11. accessDeallocatedPtrProxy: 獲取已經釋放的代理,(這個也挺常見的)

    
    注:相關崩潰信息和 accessDeallocatedObject 一致
    
    - (void) accessDeallocatedPtrProxy
    {
        RefHolder* ref = [RefHolder new];
        ref.ref = [MyProxy alloc];
    
        dispatch_async(dispatch_get_main_queue(), ^
        {
           NSLog(@"Object = %@", ref.ref);
        });
    }
  12. deadlock: 線程死鎖

    - (void) deadlock
    {
        [self.lock lock];
        [NSThread sleepForTimeInterval:0.2f];
        dispatch_async(dispatch_get_main_queue(), ^
       {
           [self.lock lock];
       });
    }
    
  13. NSExcetion: iOS 自帶崩潰信息

    這種崩潰一蹦可以通過 iOS 的自帶方法檢測處理啊,調用 NSSetUncaughtExceptionHandler 這個方法可以設置異常捕捉的回調方法,發生異常時系統回回調該方法,做好日誌保存上傳即可,注意,在使用第三方異常捕捉工具時請記住鏈式傳遞,否則會導致第三方捕捉工具無法正常使用的問題。
    例如:
    previousUncaughtExceptionHandler = NSGetUncaughtExceptionHandler();
    系統我們方法之後再調用 previousUncaughtExceptionHandler(excetion)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章