一 野指针
C语言
当我们声明1个指针变量,没有为这个指针变量赋初始值.这个指针变量的值是1个垃圾指 指向1块随机的内存空间。
OC语言:
指针指向的对象已经被回收掉了.这个指针就叫做野指针。
二 僵尸对象
一个OC对象引用计数为0被释放
后就变成僵尸对象了,僵尸对象的内存已经被系统回收,虽然可能该对象还存在,数据依然在内存中,但僵尸对象已经是不稳定对象了,不可以再访问或者使用,它的内存是随时可能被别的对象申请而占用的。
僵尸对象: 1个已经被释放的对象 就叫做僵尸对象.
1.内存回收的本质
- 申请1块空间,实际上是向系统申请1块别人不再使用的空间.
- 释放1块空间,指的是占用的空间不再使用,这个时候系统可以分配给别人去使用.
- 在这个个空间分配给别人之前 数据还是存在的.
- OC对象释放以后,表示OC对象占用的空间可以分配给别人.
- 但是再分配给别人之前 这个空间仍然存在 对象的数据仍然存在.
2.使用野指针访问僵尸对象
.有的时候会出问题报错(EXC_BAD_ACCESS
),有的时候不会出问题.
- 当野指针指向的僵尸对象所占用的空间还没有分配给别人的时候,这个时候其实是可以访问的.因为对象的数据还在.
- 当野指针指向的对象所占用的空间分配给了别人的时候 这个时候访问就会出问题. 所以,你不要通过1个野指针去访问1个僵尸对象.
- 虽然可以通过野指针去访问已经被释放的对象,但是我们不允许这么做.
3.僵尸对象检测.
- 默认情况下. Xcode不会去检测指针指向的对象是否为1个僵尸对象. 能访问就访问 不能访问就报错.
- 可以开启Xcode的
僵尸对象检测
.- 那么就会在通过指针访问对象的时候,检测这个对象是否为1个僵尸对象 如果是僵尸对象 就会报错.
4.为什么不默认开启僵尸对象检测呢?
- 因为一旦开启,每次通过指针访问对象的时候.都会去检查指针指向的对象是否为僵尸对象.
- 那么这样的话 就影响效率了.
5.如何避免僵尸对象报错.
当1个指针变为野指针以后. 就把这个指针的值设置为nil
6.僵尸对象无法复活.
- 当1个对象的引用计数器变为0以后 这个对象就被释放了.
- 就无法取操作这个僵尸对象了. 所有对这个对象的操作都是无效的.
- 因为一旦对象被回收,对象就是1个僵尸对象,而访问1个僵尸对象是没有意义.
三.空指针
空指针是指没有指向任何东西的指针(存储的东西是nil、NULL、0),给空指针发送消息不会报错
四.开启Xcode对僵尸对象检测调试
4.1 BAD_ACCESS 在什么情况下出现
BAD_ACCESS
报错属于内存访问错误,会导致程序崩溃,错误的原因是访问了野指针(悬挂指针)
。野指针指的是本来指针指向的对象已经释放了,但指向该对象的指针没有置 nil,指针指向随机的未知的内存,程序还以为该指针指向那个对象,导致存在一些潜在的危险访问操作,这些危险访问操作无法被指针指向的未知内存所处理,就会导致BAD_ACCESS错误造成程序崩溃
。访问的含义包括多种情况。
例如:
- 向野指针发送消息
- 读写野指针本来指向的对象的成员变量等等。
4.2 如何调试BAD_ACCESS错误
首先调试BAD_ACCESS错误是比较困难的,我们知道BAD_ACCESS错误是由于访问了野指针,但程序不会在野指针出现时或者在我们访问野指针的代码处报错,导致对其难以察觉,调试方法思路如下:
开启僵尸对象诊断
首先是开启僵尸对象诊断模式,利用僵尸对象来对野指针的出现位置提供线索。我们知道僵尸对象指的是引用计数为0被系统回收的对象,但这些对象暂时还存在于内存中,且理论上还是可以使用的,但是不稳定。开启僵尸对象诊断后,僵尸对象会暂时保持活跃用于调试,我们的野指针在对象回收后依然指向该僵尸对象,在访问野指针也就是访问僵尸对象
的情况下可以被编辑器检测出来。这个时候还是会报BAD_ACCESS
错误,但是后台会打印出该线索,例如下面的访问野指针打印的后台信息:
可以看出Xcode告诉我们消息发送给了一个僵尸对象,僵尸对象原本是一个实例,但现在该对象被回收了而开发者还试图访问它,由此可以很容易定位问题所在。
另外开启僵尸对象诊断的方法为:打开Xcode顶部导航栏的Product-Scheme-Edit Scheme
,在弹出的界面中选中左侧的Run模式,然后勾选右侧Dianostics
下的Zombie Objects
。
为什么不默认开启僵尸对象检测呢?
因为一旦开启,每次通过指针访问对象的时候,都会去检查指针指向的对象是否为僵尸对象。所以会影响程序的执行效率,建议关闭。
Analyze分析
僵尸对象诊断可以帮助快速定位多数情况下的野指针问题,但也有时候不能奏效,这个时候只能利用Xcode的Analyze静态分析帮助检查可能出问题的地方,仔细检查问题所在,比较费时。
使用方法很简单,选中Xcode顶部导航栏Product-Analyze或使用快捷键Command+Shift+B,分析需要花一些时间,然后左侧会列出编辑器发现的存在潜在问题的地方,选中蓝色图标对应的问题项会跳到问题项所在的代码行。但这只能给出一些潜在提示,帮助搜索问题所在,不一定和我们的bug相关。
定位到问题后把野指针至nil
本文参考 iOS-野指针与僵尸对象 ,非常感谢该作者。