iOS EXC_BAD_ACCESS的产生和调试

Crash大概可以分成两种:SIGABRTEXC_BAD_ACCESS

  • SIGABRT :是程序可以控制的崩溃,会因为应用做了系统不支持的事情而终断,简单来看,这种crash大半都是可追溯的,因为当crash发生的时候,会帮我们断点定位到可能存在问题的代码处
  • EXC_BAD_ACCESS :是全局堆栈crash,没有太多的信息可追溯,难以追踪、调试
实际场景有下面几种情况:

结论来自腾讯Bugly

  1. 对象释放后内存没被改动过,原来的内存保存完好,可能不Crash或者出现逻辑错误(随机Crash)。
  2. 对象释放后内存没被改动过,但是它自己析构的时候已经删掉某些必要的东西,可能不Crash、Crash在访问依赖的对象比如类成员上、出现逻辑错误(随机Crash)。
  3. 对象释放后内存被改动过,写上了不可访问的数据,直接就出错了很可能Crash在objc_msgSend上面(必现Crash,常见)。
  4. 对象释放后内存被改动过,写上了可以访问的数据,可能不Crash、出现逻辑错误、间接访问到不可访问的数据(随机Crash)。
  5. 对象释放后内存被改动过,写上了可以访问的数据,但是再次访问的时候执行的代码把别的数据写坏了,遇到这种Crash只能哭了(随机Crash,难度大,概率低)!!
  6. 对象释放后再次release(几乎是必现Crash,但也有例外,很常见)。

参考下面的这张图:
野指针表现形式.png

常见的调试方式:

1.NSZombie Objects --- 僵尸对象

原理:对于已经释放的对象,系统会把它标识为僵尸对象,当给这个僵尸对象发消息的时候,会出现Crash,通过系统打印的log信息我们就能够进行定位。

开启Zombie Objects

像下面这样的:

static NSMutableArray *array;
- (void)viewDidLoad {
    [super viewDidLoad];
    array = [[NSMutableArray alloc] initWithCapacity:5];
    [array release];
}
- (void) viewWillAppear:(BOOL)animated {
    [array addObject:@"Hello"];
}

运行起来之后你就会收到一条像这样的消息:

-[__NSArrayM addObject:]: message sent to deallocated instance 0x6557370

从log中可以看到,给已经释放的数组发送了一条消息。有了这些信息我们就能够比较快的进行定位代码,解决问题。(如果发生了全系统栈Crash,很多时候这个就没什么用了)

2.Address Sanitizer-地址消毒器(翻译过来是这样的🤒)

原理:当程序创建变量分配内存时,将此内存后面的一段内存也冻结住,标识为中毒内存。如图所示,黄色是变量所占内存,紫色是冻结的中毒内存。


内存示意图

当程序访问到中毒内存时(越界访问),就会抛出异常,并打印出相应的log信息。如果变量释放了,变量所占的内存也会标识为中毒内存,这时候访问这段内存同样会抛出异常(访问已经释放的对象)。

像这样的:

char *buffer;
- (void)viewDidLoad {
    [super viewDidLoad];
    unsigned size = 11;
    buffer = malloc(size);
    sprintf(buffer, "Hello World!");
    NSLog(@"%p, %s", buffer, buffer);
}

运行起来之后:


捕获到的内存越界

同样的代码,要是使用Zombie Objects选项来检测的话,是很难被发现的。因此对于 Zombie 来说 ,Address Sanitizer 拥有着更加强大的捕获能力,它们虽然功能相似,但是还是存在差异的:

Zombie VS Sanitizer

从功能上看,貌似 Sanitizer 能干一些 Zombie 所不能干的事,但是 Sanitizer 还是存在弊端的:

  • 使用 Address Sanitizer 除了分配对象的内存之外,还需要额外的内存,这会导致App内存大量增加,用起来有可能会比较卡。(仅仅考虑Debug环境,线上环境你勾选这个?苹果大爷不会让你通过审核的🙄)
  • Address Sanitizer 可能会没有log(官方的说法是显而易见的错误),不过会在访问中毒内存的代码处断住。

3.Hook对象的dealloc方法

iOS监控-野指针定位

该文章提出,我们可以通过Hook根类的dealloc方法将它重定位到我们Proxy对象的dealloc方法中来,这样当某个对象被释放的时候就会调用Proxy的dealloc方法,在该方法中让对象的isa指针指向Proxy对象,同时监听该对象消息转发的过程,如果接下来Proxy对象仍然能够收到消息的话,即抛出异常。同时为了避免内存泄露,在延时30s之后,将对象重定位回原来的类,并调用该类的dealloc方法。这样就完成了一次监听工作。


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

推荐阅读更多精彩内容

  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,293评论 8 265
  • 前言 iOS崩溃是让iOS开发人员比较头痛的事情,app崩溃了,说明代码写的有问题,这时如何快速定位到崩溃的地方很...
    齐滇大圣阅读 65,222评论 29 443
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,082评论 1 32
  • iOS面试题目100道 1.线程和进程的区别。 进程是系统进行资源分配和调度的一个独立单位,线程是进程的一个实体,...
    有度YouDo阅读 29,871评论 8 137
  • 今天很幸运,和一个小姐姐偶遇交了现场定金,这是第二次预售,最大的感触仍然是那些第一次相遇就信任我的姐姐们,想到这些...
    T久处不厌阅读 181评论 0 0