野指针:指针指向的对象已经被释放了,这个指针就叫做野指针
1. 内存回收的本质:
- 申请一块内存,实际上是向系统申请一块别人不再使用的内存空间
- 释放一块内存,实际上是占用的空间不再使用,这个时候系统就可以分配给别人去使用,但此时这个空间上还保留着之前的数据内容
2. 僵尸对象:
一个已经被释放的对象 就叫做僵尸对象
3. 不能使用野指针访问被释放的对象
4. 通过Xcode自带的工具检测僵尸对象并定位:
方法一(手动设置NSZombieEnabled环境变量):选择Product -> Scheme -> Edit Scheme -> Run(Debug) -> Diagnostics,勾选上Address zomble objects(不建议这样操作,会导致内存占用增长,影响Leaks工具的调试)
方法二(使用Zombies工具):
- 选择Xcode -> Open Developer Tool -> Instruments -> Zombies工具
- 对之前产生EXC_BAD_ACCESS的测试用例重新运行,直到程序崩溃,出现EXC_BAD_ACCESS错误
- 通过滑动箭头来查看错误细节,例如可以看到该对象的内存操作过程,如malloc、autorelease、retain、release等操作
- 查看底部的详细历史,选择相应的行可以定位到相应的代码,找出产生错误的代码
基本上通过查看Zombies工具给出的信息找出错误代码行是比较简单的,Zombies也只有在产生EXC_BAD_ACCESS错误时才有用。
注意,Zombie只能用在模拟器调试中,真机上不能使用。
Zombies工具的原理:
Zombies工具的查找原理其实和设置NSZombieEnabled环境变量的调试方式是一样的,启动Zombies后在内部设置了NSZombieEnabled为True。
启用了NSZombieEnabled的话,它会用一个僵尸来替换默认的dealloc实现,也就是在引用计数降到0时,该僵尸实现会将该对象转换成僵尸对象。僵尸对象的作用是在你向它发送消息时,就不会向之前那样Crash或者产生 一个难以理解的行为,而是放出一个错误消息,它会显示一段日志并自动跳入调试器, 因此我们就可以找到具体或者大概是哪个对象被错误的释放了。
5. 为什么不默认开启僵尸对象检测呢?
因为一旦开启,每次通过指针访问对象的时候.都会去检查指针指向的对象是否为僵尸对象.那么这样的话 就影响效率了.
6. 向野指针发送消息就会导致崩溃:
因为你访问了一块不属于你的内存,崩溃的LOG为“Thread 1:EXC_BAD_ACCESS”,野指针导致的崩溃问题是有一定的出现概率的,因为“获取野指针指向的结果是不确定的”。
解决思路是:对象已经被释放后,应将其指针置为空指针(没有指向任何对象的指针,给空指针发送消息不会报错)