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)即可