一 野指针
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。
zombie-1.png
zombie-2.png
为什么不默认开启僵尸对象检测呢?
因为一旦开启,每次通过指针访问对象的时候,都会去检查指针指向的对象是否为僵尸对象。所以会影响程序的执行效率,建议关闭。
Analyze分析
僵尸对象诊断可以帮助快速定位多数情况下的野指针问题,但也有时候不能奏效,这个时候只能利用Xcode的Analyze静态分析帮助检查可能出问题的地方,仔细检查问题所在,比较费时。
使用方法很简单,选中Xcode顶部导航栏Product-Analyze或使用快捷键Command+Shift+B,分析需要花一些时间,然后左侧会列出编辑器发现的存在潜在问题的地方,选中蓝色图标对应的问题项会跳到问题项所在的代码行。但这只能给出一些潜在提示,帮助搜索问题所在,不一定和我们的bug相关。
analyze-1.png
定位到问题后把野指针至nil
本文参考iOS-野指针与僵尸对象,非常感谢该作者。