野指针:指针指向的对象已经被释放了,这个指针就叫做野指针

1. 内存回收的本质:
  1. 申请一块内存,实际上是向系统申请一块别人不再使用的内存空间
  2. 释放一块内存,实际上是占用的空间不再使用,这个时候系统就可以分配给别人去使用,但此时这个空间上还保留着之前的数据内容
2. 僵尸对象:

一个已经被释放的对象 就叫做僵尸对象

3. 不能使用野指针访问被释放的对象
4. 通过Xcode自带的工具检测僵尸对象并定位:

方法一(手动设置NSZombieEnabled环境变量):选择Product -> Scheme -> Edit Scheme -> Run(Debug) -> Diagnostics,勾选上Address zomble objects(不建议这样操作,会导致内存占用增长,影响Leaks工具的调试)

方法二(使用Zombies工具):

  1. 选择Xcode -> Open Developer Tool -> Instruments -> Zombies工具
  2. 对之前产生EXC_BAD_ACCESS的测试用例重新运行,直到程序崩溃,出现EXC_BAD_ACCESS错误
  3. 通过滑动箭头来查看错误细节,例如可以看到该对象的内存操作过程,如malloc、autorelease、retain、release等操作
  4. 查看底部的详细历史,选择相应的行可以定位到相应的代码,找出产生错误的代码

基本上通过查看Zombies工具给出的信息找出错误代码行是比较简单的,Zombies也只有在产生EXC_BAD_ACCESS错误时才有用。

注意,Zombie只能用在模拟器调试中,真机上不能使用。

Zombies工具的原理:

Zombies工具的查找原理其实和设置NSZombieEnabled环境变量的调试方式是一样的,启动Zombies后在内部设置了NSZombieEnabled为True。

启用了NSZombieEnabled的话,它会用一个僵尸来替换默认的dealloc实现,也就是在引用计数降到0时,该僵尸实现会将该对象转换成僵尸对象。僵尸对象的作用是在你向它发送消息时,就不会向之前那样Crash或者产生 一个难以理解的行为,而是放出一个错误消息,它会显示一段日志并自动跳入调试器, 因此我们就可以找到具体或者大概是哪个对象被错误的释放了。
5. 为什么不默认开启僵尸对象检测呢?

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

6. 向野指针发送消息就会导致崩溃:

因为你访问了一块不属于你的内存,崩溃的LOG为“Thread 1:EXC_BAD_ACCESS”,野指针导致的崩溃问题是有一定的出现概率的,因为“获取野指针指向的结果是不确定的”。

解决思路是:对象已经被释放后,应将其指针置为空指针(没有指向任何对象的指针,给空指针发送消息不会报错)