如何检测野指针?

啥是野指针?

  • 指向一个已经删除的对象或未申请访问受限内存区域的指针。而这里的野指针主要是指对象释放后,指针未置空导致的野指针。该类Crash发生比较随机,找出来比较费劲,比较常见的做法是在开发阶段就提高这类Crash的复现率,尽可能的将其发现并解决。

  • 向OC对象发出release消息,只是标记对象占用的那块内存可以被释放,系统并没有立即收回内存;如果此时还向该对象发送其他消息,可能会发生Crash,也可能没有问题。

  • 野指针造成的Crash随机性比较大,但是被随机填入的数据是不可访问的情况下,Crash是必现的。

  • 解决思路是:想办法给野指针指向的内存填写不可访问的数据,让随机的Crash变成必现的Crash。

如何定位野指针

1.内存涂鸦(Malloc Scribble)
Xcode提供的Malloc Scribble,可以将对象释放后在内存上填上不可访问的数据,将随机发生变成不随机发生的事情,选中Product->Scheme->Edit Scheme ->Diagnostics – >勾选 Malloc Scribble项,结果如下:

271cfd6e1028f577e5dd49e4e3f593db.png

设置了Enable Scribble,在对象申请内存后在申请的内存上填0xaa,内存释放后在释放的内存上填0x55;如果内存未被初始化就被访问,或者释放后被访问,Crash必现。
Warning:该方法必须连接Xcode运行代码才能发现,并不适合测试人员使用。

  1. 僵尸对象(NSZombieEnabled)
  • 内存已经被回收的对象。
  • 简单的来说,僵尸对象是已经被释放的对象。如果在程序中再度使用该对象,一般会出现如下报错:
unrecognized selector sent to instance  .

默认情况下. Xcode不会去检测指针指向的对象是否为1个僵尸对象. 能访问就访问 不能访问就报错.

// 首先判断对象a是否还存在,如存在,执行mehtod方法;若不存在,此时就是对象a就是僵尸对象,此时如果不判断直接调用method方法,就会crash
if(!a){
   a = [[A alloc] init];
}
[a method];

Xcode提供的NSZombieEnabled,通过生成僵尸对象来替换dealloc的实现,当对象引用计数为0 的时候,将需要dealloc的对象转化为僵尸对象。如果之后再给这个僵尸对象发消息则抛异常。先选中Product -> Scheme -> Edit Scheme -> Diagnostics -> 勾选Zombie Objects 项,显示如下:

72537f67f7ad85f98f22adc17fb9d06b.png

然后在Product -> Scheme -> Edit Scheme -> Arguments设置NSZombieEnabled、MallocStackLoggingNoCompact两个变量,且值均为YES。显示如下:


3f07ccbc098736b06caab7cd4e3715fd.png
  • 仅设置Zombie Objects的话,如果Crash发生在当前调用栈,系统可以把崩溃原因定位到具体代码中;但是如果Crash不是发生在当前调用栈,系统仅仅告知崩溃地址,所以需要添加变量。MallocStackLoggingNoCompact,让Xcode记录每个地址alloc的历史,然后通过命令将地址还原出来。

注意:发版前要将僵尸对象检测这些设置都去掉,否则每次通过指针访问对象时,都去检查指针指向的对象是否为僵尸对象,这就影响效率了。

为什么不默认开启僵尸对象检测呢?

因为一旦开启,每次通过指针访问对象的时候.都会去检查指针指向的对象是否为僵尸对象.
那么这样的话 就影响效率了.

  • 如何避免僵尸对象报错.
    • 当1个指针变为野指针以后. 就把这个指针的值设置为nil
  • 僵尸对象无法复活.
    • 当1个对象的引用计数器变为0以后 这个对象就被释放了。
    • 就无法取操作这个僵尸对象了,所有对这个对象的操作都是无效的。

因为一旦对象被回收,对象就是1个僵尸对象,而访问1个僵尸对象是没有意义。

如何定位Obj-C野指针随机Crash(一):先提高野指针Crash率
如何定位Obj-C野指针随机Crash(二):让非必现Crash变成必现
如何定位Obj-C野指针随机Crash(三):加点黑科技让Crash自报家门

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • [这是第15篇] 导语:在当前的iOS开发中,虽然ARC为开发者解决了手动内存管理时代 的许多麻烦,但是内存方面的...
    南华coder阅读 7,559评论 10 78
  • 成因 野指针就是指向一个已删除的对象或者受限内存区域的指针。我们写C++的时候强调指针初始化为NULL,强调用完后...
    上官soyo阅读 21,037评论 4 80
  • 一、Instruments介绍 Instruments 一个很灵活的、强大的工具,是性能分析、动态跟踪 和分析OS...
    音符上的码字员阅读 17,668评论 0 31
  • 崩溃分析 崩溃日志(crash log) 根据符号表来监测崩溃位置 什么是符号表符号表就是指在Xcode项目编译后...
    纸简书生阅读 5,770评论 0 17
  • 我们曾在一起高谈阔论,调侃父母之间的摩擦。自认为父母之间的矛盾没什么是不能打一炮解决的,如果有,那就打两炮。 ...
    唯佳裳安阅读 173评论 0 0