iOS crash 問(wèn)題梳理總結(jié)

1.[CIContext createCGImage:fromRect:]調(diào)用崩潰

SIGSEGV
SEGV_ACCERR

libsystem_platform.dylib
__platform_memmove
1
AGXGLDriver
_gldUpdateDispatch
2
AGXCompilerConnection
CompilerFSCacheGetShaderCacheKeys(CompilerFSCache const*)
3
libdispatch.dylib
__dispatch_client_callout
4
libdispatch.dylib
__dispatch_lane_barrier_sync_invoke_and_complete
5
AGXCompilerConnection
0x00000001a58ed000 + 5124
6
libdispatch.dylib
__dispatch_client_callout
7
libdispatch.dylib
__dispatch_lane_barrier_sync_invoke_and_complete
8
AGXCompilerConnection
0x00000001a58ed000 + 3316
9
AGXGLDriver
_gldUpdateDispatch
10
AGXGLDriver
_gldGetDeviceString
11
AGXGLDriver
_gldUnbindPipelineProgram
12
AGXGLDriver
_gldUpdateDispatch
13
GLEngine
_gleDoDrawDispatchCoreES2
26
CoreImage
-[CIContext createCGImage:fromRect:]

根據(jù)上述堆??梢远ㄎ坏奖罎⒌搅诉@里,在調(diào)用context createCGImage:方法時(shí)發(fā)生了異常

CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef outImage = [context createCGImage:outputImage fromRect:[inputImage extent]];

因?yàn)閕OS不能在后臺(tái)使用opengl,所以懷疑是因?yàn)檫@個(gè)原因,這里有兩種修復(fù)方式:

  • 方式一:
    在調(diào)用該方法時(shí)加入前后臺(tái)邏輯判斷,后臺(tái)情況不進(jìn)行繪制
  • 方式二:
    在 CIContext 創(chuàng)建的時(shí)候,我們可以給它設(shè)置為基于 GPU 還是 CPU。

Core Image 的另外一個(gè)優(yōu)勢(shì),就是可以根據(jù)需求選擇 CPU 或者 GPU 來(lái)處理。在 CIContext 創(chuàng)建的時(shí)候,我們可以給它設(shè)置為基于 GPU 還是 CPU。

基于 GPU 的話,處理速度更快。以為利用了 GPU 的硬件并行優(yōu)勢(shì)。可以使用 OpenGL ES 或者 Metal 來(lái)渲染圖像。這種方式 CPU 完全沒(méi)有負(fù)擔(dān),應(yīng)用程序的運(yùn)行循環(huán)不會(huì)受到圖像渲染的影響。

但是 GPU 受限于硬件紋理尺寸,而且如果你的程序在后臺(tái)繼續(xù)處理和保存圖片的話,那么需要使用 CPU。因?yàn)楫?dāng)應(yīng)用切換到后臺(tái)狀態(tài)時(shí),GPU 處理會(huì)被打斷。使用 CPU 渲染的 iOS 會(huì)采用 GCD 來(lái)對(duì)圖像進(jìn)行渲染。這保證了 CPU 渲染在大部分情況下更可靠,比 GPU 渲染更容易使用,可以在后臺(tái)實(shí)現(xiàn)渲染過(guò)程。

綜上,對(duì)于復(fù)雜圖像濾鏡,使用 GPU 更好。但如果在處理視頻過(guò)程中,保存文件或保存照片到照片庫(kù)中時(shí),為避免程序進(jìn)入后臺(tái)對(duì)圖片保存造成影響,這時(shí)應(yīng)該使用 CPU 進(jìn)行渲染。

這里修復(fù)我采用的是第二種方式,經(jīng)驗(yàn)證,問(wèn)題已修復(fù)

CIContext *context = nil;
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
if (device == nil) {
   context = [CIContext contextWithOptions:@{ kCIContextUseSoftwareRenderer: @(YES), kCIContextCacheIntermediates: @(NO) }];
 } else {
 context = [CIContext contextWithMTLDevice:device options:@{ kCIContextCacheIntermediates: @(NO) }];
}
CGImageRef outImage = [context createCGImage:outputImage fromRect:[inputImage extent]];

2.NSMallocException Failed to grow buffer

崩潰堆棧信息

1
libobjc.A.dylib
_objc_exception_throw
2
Foundation
__NSInitializePlatform
3
CoreFoundation
___CFReallocationFailed
4
CoreFoundation
___CFSafelyReallocate
5
Foundation
__convertJSONString
6
Foundation
__writeJSONString
7
Foundation
____writeJSONObject_block_invoke
8
CoreFoundation
-[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:]
9
Foundation
__writeJSONObject
10
Foundation
____writeJSONArray_block_invoke
11
CoreFoundation
-[__NSArrayM enumerateObjectsWithOptions:usingBlock:]
12
Foundation
__writeJSONArray
13
Foundation
____writeJSONObject_block_invoke
14
CoreFoundation
-[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:]
15
Foundation
__writeJSONObject
16
Foundation
-[_NSJSONWriter dataWithRootObject:options:error:]
17
Foundation
+[NSJSONSerialization dataWithJSONObject:options:error:]

"Failed to grow buffer"表示在嘗試擴(kuò)展緩沖區(qū)時(shí)出現(xiàn)了問(wèn)題,這種崩潰通常發(fā)生在使用動(dòng)態(tài)內(nèi)存分配函數(shù)(如malloc、realloc等)時(shí),當(dāng)嘗試分配的內(nèi)存大小超過(guò)了系統(tǒng)可用的內(nèi)存大小時(shí),就會(huì)拋出這種異常。

查看堆棧信息,最后是在調(diào)用[NSJSONSerialization dataWithJSONObject:options:error:]方法時(shí)發(fā)生了異常,也就是當(dāng)object過(guò)大時(shí)發(fā)生的,這里可以采用以下方式進(jìn)行防御,但是在實(shí)際開(kāi)發(fā)中,建議不要?jiǎng)?chuàng)建較大的object,優(yōu)化上層邏輯,避免出現(xiàn)這種情況

    NSData *jsonData = nil;
    @try {
        jsonData = [NSJSONSerialization dataWithJSONObject:object options:options error:nil];
    } @catch (NSException *exception) {
        EduAssert(false, @"NSString+NSJson jsonStringForNSJsonData [NSJSONSerialization dataWithJSONObject:]  is failed! exception occurred: %@",
            exception);
        LogE(gLogTag, @"NSString+NSJson jsonStringForNSJsonData [NSJSONSerialization dataWithJSONObject:]  is failed! exception occurred: %@",
            exception);
        return nil;
    }

3. SIGABRT libsystem_kernel.dylib ___pthread_kill + 8

崩潰堆棧
0
libsystem_kernel.dylib
___pthread_kill + 8
1
libsystem_pthread.dylib
_pthread_kill + 268
2
libsystem_c.dylib
_abort + 180
3
libsystem_malloc.dylib
_malloc_vreport + 908
4
libsystem_malloc.dylib
_malloc_zone_error + 100
5
libsystem_malloc.dylib
_nanov2_guard_corruption_detected + 44
6
libsystem_malloc.dylib
_nanov2_free_definite_size
7
libsystem_c.dylib
_strdup + 40
8
ImageIO
_yylex + 2004
9
ImageIO
_yyparse + 244
10
ImageIO
_parse_metadata_path + 88
11
ImageIO
_parse_metadata_pathString + 56
12
ImageIO
_CGImageMetadataGetTagWithPath + 396
13
ImageIO
___CGImageMetadataCreateFromLegacyProps_block_invoke + 1920
14
ImageIO
_XMPMappingIteratePropertiesUsingBlock + 476
15
ImageIO
_CGImageMetadataCreateFromLegacyProps + 148
16
ImageIO
CopyTiffPropertiesToRoot(IIODictionary, CGImageMetadata) + 400
17
ImageIO
IIOImageSource::makeImagePlus(unsigned long, IIODictionary) + 820
18
ImageIO
IIOImageSource::createImageAtIndex(unsigned long, IIODictionary
) + 80
19
ImageIO
_CGImageSourceCreateImageAtIndex + 276

這里根據(jù)堆棧信息,是在調(diào)用CGImageRef frame = CGImageSourceCreateImageAtIndex([self imageCache], i, NULL);方法時(shí)發(fā)生了異常,當(dāng)[self imageCache]被提前釋放的時(shí)候,調(diào)用就會(huì)出現(xiàn)野指針崩潰的問(wèn)題,所以此處需要注意的是,當(dāng)[self imageCache]被很多地方調(diào)用的時(shí)候,就有可能出現(xiàn)野指針的情況,可以通過(guò)加鎖,并在CFRelease的時(shí)候加上安全判斷來(lái)修復(fù)

    for (size_t i = 0; i < frameCount; ++i) {
        // get each frame
        CGImageRef frame = CGImageSourceCreateImageAtIndex([self imageCache], i, NULL);
        [frames addObject:(id)frame];
        CGImageRelease(frame);

修復(fù)代碼如下:

+ (CGImageSourceRef)imageCache {
    [gLock lock];
    CGImageSourceRef ref = imageCache;
    [gLock unlock];
    return ref;
}

+ (void)setImageCache:(CGImageSourceRef)ref {
    [gLock lock];
    imageCache = ref;
    [gLock unlock];
}

+ (void)safeRelease {
    if (imageCache == NULL) {
        return;
    }
    CFRelease(imageCache);
    imageCache = NULL;
}

4. Application tried to present modally a view controller <EduLivePlayerController: 0x1321c4600> that is already being presented by <EduTabBarController: 0x1328c3200>.

這個(gè)crash 表示應(yīng)用程序試圖以模態(tài)方式呈現(xiàn)一個(gè)已經(jīng)在顯示中的視圖控制器,即要彈出控制器B,而控制器B已經(jīng)被彈出或者正在被彈出的時(shí)候又調(diào)用了一次present(B)

修復(fù)方案:
在present B之前添加判斷:
當(dāng)前的presentedViewController != B && B.presentingViewController == nil

5.野指針崩潰 SIGSEGV SEGV_ACCERR

0 Thread
SIGSEGV
SEGV_ACCERR

0
libobjc.A.dylib
_objc_release_x0
19
CoreFoundation
-[__NSArrayM dealloc]
20
xxxxx
-EduGifView clear
21
xxxxx
-EduFloatView dealloc

這里通過(guò)堆棧信息可以看到,在調(diào)用dealloc方法釋放數(shù)組時(shí),數(shù)組中的元素在其他地方同時(shí)在使用,導(dǎo)致的野指針crash,因此這里可以考慮將數(shù)組加鎖防止釋放同時(shí)在使用

6.CALayerInvalidGeometry

當(dāng)CALayer的位置或大小屬性包含了無(wú)效的值,例如NaN(Not a Number)等

崩潰堆棧信息:
0 Thread
CALayerInvalidGeometry
CALayer position contains NaN: [nan nan]. Layer: <CAEAGLLayer:0x281b576f0; position = CGPoint (282.375 408.625); bounds = CGRect (0 0; 512 288); delegate = <IJKSDLGLView: 0x2c2683430; frame = (26.375 264.625; 512 288); autoresize = LM+W+RM+TM+H+BM; tintColor = UIExtendedSRGBColorSpace 0.137255 0.721569 1 1; layer = <CAEAGLLayer: 0x281b576f0>>; contents = <CAImageQueue 0x10aa30e70>; allowsDisplayCompositing = YES; allowsGroupOpacity = YES; contentsScale = 2; backgroundColor = <CGColor 0x283480500> [<CGColorSpace 0x2833e6ac0> (kCGColorSpaceICCBased; kCGColorSpaceModelMonochrome; ê??è??á?∞?∫?á≥aê?∞2.2êèè??∞ê?á‰a?; extended range)] ( 0 1 ); drawableProperties = { EAGLDrawablePropertyColorFormat = EAGLColorFormat8888; EAGLDrawablePropertyRetained = 0; }>

0
CoreFoundation
___exceptionPreprocess
6
UIKitCore
-[UIView(Geometry) setFrame:]

根據(jù)上述堆棧信息,可以看到在給view設(shè)置frame的時(shí)候出現(xiàn)了nan這種無(wú)效值,所以引發(fā)的崩潰,可以查看frame的計(jì)算賦值,是否有nan的情況,要特別注意是否有除數(shù)為0的可能性

7.數(shù)組越界

NSRangeException
*** -[__NSArrayM objectAtIndex:]: index 21 beyond bounds [0 .. 20]

這個(gè)比較常見(jiàn),通過(guò)判斷數(shù)組長(zhǎng)度和下標(biāo)即可

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

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

  • Incident Identifier: 1AD94B5F-91DB-4622-A2CF-3F1C8AE8A376...
    我會(huì)回來(lái)的閱讀 4,152評(píng)論 0 2
  • 今天碰巧下載了QQ瀏覽器iOS版本,居然一啟動(dòng)就掛了。后來(lái)從手機(jī)里面把崩潰信息導(dǎo)出來(lái),仔細(xì)研究下,把研究的結(jié)果放到...
    yqmfly閱讀 3,259評(píng)論 1 1
  • 關(guān)鍵時(shí)刻,第一時(shí)間送達(dá)! 問(wèn)題種類(lèi) 時(shí)間復(fù)雜度 在集合里數(shù)據(jù)量小的情況下時(shí)間復(fù)雜度對(duì)于性能的影響看起來(lái)微乎其微。但...
    C9090閱讀 1,029評(píng)論 0 1
  • 首先如果遇到應(yīng)用卡頓或者因?yàn)閮?nèi)存占用過(guò)多時(shí)一般使用Instruments里的來(lái)進(jìn)行檢測(cè)。但對(duì)于復(fù)雜情況可能就需要用...
    攻克乃還_閱讀 2,250評(píng)論 0 7
  • 本文分析了一份標(biāo)準(zhǔn)的iOS應(yīng)用程序的Crash報(bào)告,它通常由以下6個(gè)部分組成。 1. 報(bào)告頭(Header) 報(bào)告...
    wo一人兩袖清風(fēng)閱讀 1,195評(píng)論 0 0

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