iOS crash 问题梳理总结

1.[CIContext createCGImage:fromRect:]调用崩溃

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:]

根据上述堆栈可以定位到崩溃到了这里,在调用context createCGImage:方法时发生了异常

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

因为iOS不能在后台使用opengl,所以怀疑是因为这个原因,这里有两种修复方式:

  • 方式一:
    在调用该方法时加入前后台逻辑判断,后台情况不进行绘制
  • 方式二:
    在 CIContext 创建的时候,我们可以给它设置为基于 GPU 还是 CPU。

Core Image 的另外一个优势,就是可以根据需求选择 CPU 或者 GPU 来处理。在 CIContext 创建的时候,我们可以给它设置为基于 GPU 还是 CPU。

基于 GPU 的话,处理速度更快。以为利用了 GPU 的硬件并行优势。可以使用 OpenGL ES 或者 Metal 来渲染图像。这种方式 CPU 完全没有负担,应用程序的运行循环不会受到图像渲染的影响。

但是 GPU 受限于硬件纹理尺寸,而且如果你的程序在后台继续处理和保存图片的话,那么需要使用 CPU。因为当应用切换到后台状态时,GPU 处理会被打断。使用 CPU 渲染的 iOS 会采用 GCD 来对图像进行渲染。这保证了 CPU 渲染在大部分情况下更可靠,比 GPU 渲染更容易使用,可以在后台实现渲染过程。

综上,对于复杂图像滤镜,使用 GPU 更好。但如果在处理视频过程中,保存文件或保存照片到照片库中时,为避免程序进入后台对图片保存造成影响,这时应该使用 CPU 进行渲染。

这里修复我采用的是第二种方式,经验证,问题已修复

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"表示在尝试扩展缓冲区时出现了问题,这种崩溃通常发生在使用动态内存分配函数(如malloc、realloc等)时,当尝试分配的内存大小超过了系统可用的内存大小时,就会抛出这种异常。

查看堆栈信息,最后是在调用[NSJSONSerialization dataWithJSONObject:options:error:]方法时发生了异常,也就是当object过大时发生的,这里可以采用以下方式进行防御,但是在实际开发中,建议不要创建较大的object,优化上层逻辑,避免出现这种情况

    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

这里根据堆栈信息,是在调用CGImageRef frame = CGImageSourceCreateImageAtIndex([self imageCache], i, NULL);方法时发生了异常,当[self imageCache]被提前释放的时候,调用就会出现野指针崩溃的问题,所以此处需要注意的是,当[self imageCache]被很多地方调用的时候,就有可能出现野指针的情况,可以通过加锁,并在CFRelease的时候加上安全判断来修复

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

修复代码如下:

+ (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>.

这个crash 表示应用程序试图以模态方式呈现一个已经在显示中的视图控制器,即要弹出控制器B,而控制器B已经被弹出或者正在被弹出的时候又调用了一次present(B)

修复方案:
在present B之前添加判断:
当前的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

这里通过堆栈信息可以看到,在调用dealloc方法释放数组时,数组中的元素在其他地方同时在使用,导致的野指针crash,因此这里可以考虑将数组加锁防止释放同时在使用

6.CALayerInvalidGeometry

当CALayer的位置或大小属性包含了无效的值,例如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; 普通灰度系数2.2描述文件; extended range)] ( 0 1 ); drawableProperties = { EAGLDrawablePropertyColorFormat = EAGLColorFormat8888; EAGLDrawablePropertyRetained = 0; }>

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

根据上述堆栈信息,可以看到在给view设置frame的时候出现了nan这种无效值,所以引发的崩溃,可以查看frame的计算赋值,是否有nan的情况,要特别注意是否有除数为0的可能性

7.数组越界

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

这个比较常见,通过判断数组长度和下标即可

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容

  • Incident Identifier: 1AD94B5F-91DB-4622-A2CF-3F1C8AE8A376...
    我会回来的阅读 3,520评论 0 2
  • 今天碰巧下载了QQ浏览器iOS版本,居然一启动就挂了。后来从手机里面把崩溃信息导出来,仔细研究下,把研究的结果放到...
    yqmfly阅读 2,928评论 1 1
  • 关键时刻,第一时间送达! 问题种类 时间复杂度 在集合里数据量小的情况下时间复杂度对于性能的影响看起来微乎其微。但...
    C9090阅读 867评论 0 1
  • 首先如果遇到应用卡顿或者因为内存占用过多时一般使用Instruments里的来进行检测。但对于复杂情况可能就需要用...
    攻克乃还_阅读 1,795评论 0 7
  • 本文分析了一份标准的iOS应用程序的Crash报告,它通常由以下6个部分组成。 1. 报告头(Header) 报告...
    wo一人两袖清风阅读 1,075评论 0 0