iOS 野指针与僵尸对象

638 阅读5分钟

野指针

野指针和空指针是不一样的,空指针没有储存任何的内存地址,而野指针指向一块内存地址,这块内存指向的对象已经被释放了,该内存是不可用的,访问野指针可能会导致程序崩溃

僵死对象

在OC中,对象被释放后所占用的内存在没有被复写(重新分配给其他对象)前称为僵尸对象,这时野指针是可以访问该内存的,因为对象的数据还在,所以程序不会报错。但是该内存一旦重新分配给其他对象就会出现问题。

  • 举例:
Person *p =[[Person alloc]init];
[p setName:@"wang"];
[p release]; //指针p指向的对象已经被释放,但是该指针还能访问该内存地址
[p setName:@"zhao"]; //所以此处不会报错

这种情况下被释放掉的对象就会成为僵尸对象。僵尸对象很可能会导致代码crash。因为系统随时会将该内存块重新分配

内存回收的本质

  • 申请1块空间,实际上是向系统申请1块别人不再使用的空间.
  • 释放1块空间,指的是占用的空间不再使用,这个时候系统可以分配给别人去使用,在这个空间分配给别人之前 数据还是存在的.

注意: OC对象释放,表示OC对象占用的空间可以分配给别人,但是再分配给别人之前,这个空间的象的数据仍然存在.

  • 使用野指针访问僵尸对象,有时候会出问题报错(EXC_BAD_ACCESS),有的时候不会出问题。 1,当野指针指向的僵尸对象所占用的空间还没有分配给别人的时候,这个时候其实是可以访问的。因为对象的数据还在。 2, 当野指针指向的对象所占用的空间分配给了别人,这个时候访问就会出问题.。所以你不要通过1个野指针去访问1个僵尸对象。

僵尸对象检测

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

  • 开启Xcode的僵尸对象检测后,就会在通过指针访问对象的时候,检测这个对象是否为僵尸对象,如果是僵尸对象就会报错。

  • 为什么不默认开启僵尸对象检测呢? 因为一旦开启,每次通过指针访问对象的时候,都会去检查指针指向的对象是否为僵尸对象, 这样的 就影响效率了

  • 如何避免僵尸对象报错? 当指针变为野指针以后就把指针的值设置为nil,访问nil不会报错。

EXC_BAD_ACCESS 在什么情况下出现

BAD_ACCESS 报错属于内存访问错误,会导致程序崩溃,错误的原因是访问了野指针。野指针是指针指向的对象已经释放了,但指向该对象的指针没有置 nil,指针指向未知的内存,程序还以为该指针指向原来的对象,导致存在一些潜在的危险访问操作,这些危险访问操作无法被指针指向的未知内存所处理,就会导致BAD_ACCESS错误造成程序崩溃。出现这种情况的原因很多。

例如:

  • 向野指针发送消息

  • 调用野指针本来指向的对象的成员变量、方法等。

如何调试BAD_ACCESS错误

首先调试BAD_ACCESS错误是比较困难的,我们知道BAD_ACCESS错误是由于访问了野指针,但程序不会在野指针出现时或者在我们访问野指针的代码处报错,导致对其难以察觉,调试方法思路如下:

Xcode开启检测僵尸对象

所以虽然可以通过野指针去访问已经被释放的对象,但是我们不允许这么做。在编码的时候就要去检测僵尸对象。

image.png

image.png 这样在[person release]之后

person对象被释放了,由于scheme开启了僵尸对象选项,所以person对象在释放时调用的dealloc方法在底层被swizzle了

dealloc方法执行时,代码走的并不是清理资源,回收内存。而是调用__dealloc_zombie方法,创建一个NSZombie对象,并修改person对象的isa指针,指向僵尸类_NSZombie_Person。所以在[person release]执行之后, 打印的person对象类型为_NSZombie_Person

_NSZombie_Person类中只有一个isa指针,里面没有其他的属性和方法,所以不能响应任何事件,所以在向这个僵尸对象发送消息时,就会报错,并打印出来。这非常有利于调试。

Analyze分析

开启僵尸对象诊断可以帮助快速定位多数情况下的野指针问题,但也有时候不能奏效,这个时候只能利用Xcode的Analyze静态分析帮助检查可能出问题的地方。

Xcode Analyze 是苹果的开发工具 Xcode 自带的一个静态分析工具,功能强大且使用简单,主要会对代码中的几类错误加以标识:

1,逻辑缺陷: 访问空指针或未初始化的变量

2, 内存管理错误: 如内存泄漏

3,无用逻辑: 永远不会被访问的变量、永远不会执行的代码;

4,Api调用错误: 未包含使用的库和框架

参考: iOS-野指针,僵尸对象,空指针详解