1.什么是对象的释放
首先我们要知道,一个对象在初始化的时候需要申请一段内存空间,同时不让别人再使用这段内存空间。
一个对象被释放了,也就是说它不再拥有这段内存空间了,其他对象可以使用这段内存空间,而不是说这个内存被销毁了不存在了。
2.什么是野指针
一个指针指向的对象已经被释放了,那这个指针就是野指针。在oc里我们应该及时给野指针赋值为nil。
⚠️:野指针也叫悬垂指针。
3.什么是僵尸对象
一个已经被释放的对象就是僵尸对象。
4.野指针访问僵尸对象
野指针访问僵尸对象不一定会crash,因为一个对象变成僵尸对象以后它原来所拥有的内存空间可能被覆写了,也可能没有被覆写,如果被覆写了那么再访问就会crash,如果没覆写就不会出问题。
5.避免野指针访问僵尸对象crash
首先我们应该避免野指针的存在,在一个指针指向的对象被释放以后把这个指针赋值为nil,这个指针就变成了空指针。给nil对象发消息不会crash。
6.什么是空指针
空指针和野指针是不一样的,没有存储任何内存地址的指针就称为空指针(NULL指针)。被赋值为nil的指针就是空指针。
7.用僵尸对象调试内存管理问题
在Xcode中,我们可以通过设置环境变量NSZombieEnabled=YES来启用僵尸对象调试内存管理问题。这里面所说的就是在我们启用了这个功能以后,那些已经被释放的对象就会被标记为僵尸对象,然后他们原来所申请的内存不会被覆写,当程序在运行过程中给僵尸对象发送消息的时候就会crash,并打印错误信息。
❓:系统怎么把一个对象标记为僵尸对象呢?
在运行时,当系统发现类A的对象要变成僵尸对象以后,就会创建一个对应的_NSZombie_A类。然后把这个对象转化成_NSZombie_A类的对象。实现过程用到了runtime的swizzle,把原有类的dealloc方法变为系统重新生成的一份代码。这个转换过程其实是由objc_duplicateClass()完成的,也就是把_NSZombie类结构拷贝一份,并命名为_NSZombie_A。这样做既把原对象转化成了僵尸对象,还保留了原有类的名称。
原有类对象的isa指针指向了僵尸类,僵尸类可以响应所有的选择子,响应方式为打印一条包含消息内容及其接受这的信息,然后终止程序。
8.常用的监测内存问题的调试技巧
当程序运行过程中crash并报错:EXC_BAD_ACCESS的时候,我们知道发生了野指针异常错误。这个时候我们开始调试。
1.用僵尸对象监测野指针异常
再次运行的时候依然会报错,但是打印出了有用信息:
MemoryProblems[54738:7483231] *** -[ArrayDataSource retain]: message sent to deallocated instance 0x7fe7025d1920
这个时候我们继续运行程序,就会发现有一个对象前面用_NSZombie修饰,并且内存地址就是0x7fe7025d1920,我们就知道了,这个对象就是引发错误的僵尸对象。
2.静态分析Product -> Analysis
静态分析其实就是在程序没有运行的时候静态的检查你的代码,看有没有出现一些错误,静态分析可以帮我们初步发现一些问题。
3.使用Instrument里的Leaks工具检测内存泄漏
程序运行过程中如果出现了内存泄漏,leak check那个地方就会有红色的叉叉,点击红色叉叉定位到引发内存泄漏的位置,双击,直接定位到代码。
4.block循环引用检测
block循环引用用静态分析,Leaks工具都检测不出来,这个时候我们就回到最原始的方法,重写类的dealloc方法,如果dealloc方法被调用了说明这个类对象被正确释放了,如果没有被调用,说明某个属性对象还被持有,没有释放。
参考文章:iOS内存管理:内存泄露调试的常用技巧
网友评论