iOS之MRC与ARC
MRC & ARC
内存管理模型
一. 需要进行内存管理的对象
- 任何继承了NSObject的对象需要进行内存管理
- 非对象类型(int、char、float、double、struct、enum等) 不需要进行内存管理
二. 内存结构
1. 堆
一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收,分配方式类似于链表,继承了NSObject的对象存储在堆中。
2. 栈
由操作系统自动分配释放,存放函数的参数值,局部变量的值等,分配方式类似于栈。
3. 数据段(data区)
4. 代码段(text区)
三. OC内存管理模型
1. 自动垃圾收集(iOS运行环境不支持)
2. 手动引用计数(MRC)和自动释放池(AutoReleasePool)
3. 自动引用计数(ARC)
四. MRC & AutoReleasePool – 手动引用计数与自动释放池
1. 引用计数器
引用计数器是一个整数,即对象被引用的次数。系统根据对象的引用计数器判断何时应该回收它所占用的内存。每个OC对象都有自己的引用计数器,任何对象刚创建的时候,引用计数器为1。
2. 引用计数器的操作
每当创建引用到对象需要给对象发送一条retain消息,此时该对象引用计数器值**+1。**
每当不需要该对象时给对象发送一条release消息,此时该对象引用计数器值**-1**
给对象发送retainCount消息,可以获得当前对象引用计数器值。
当对象的引用计数器值为0时,系统通过给该对象发送dealloc消息,释放该对象的内存。
3. dealloc
- 对象即将被销毁时系统会自动给对象发送一条dealloc消息。
- 一般会重写dealloc方法,即在这里释放相关资源,该方法一旦重写,必须在方法最后调用**[super dealloc]**。
- 不能直接调用dealloc方法。
4. 野指针和空指针
- 当一个指针指向一个“僵尸对象”(被释放了的对象),这个指针就是野指针。
- 为避免给野指针发送消息报错,在它指向的对象被释放后,将它设置为空指针(没有指向存储空间的指针)。
5. 自动释放池 – AutoReleasePool
autorelease是一种支持引用计数的内存管理方式,给对象发送一条autorelease信息,会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子中的所有对象发送一次release消息(只是发送release消息,并不是将对象直接释放)。
autorelease方法会返回对象本身,其实质上是延迟了给对象发送release消息的操作。
NSAutoreleasePool *pool创建等同与@autoreleasepool创建,前者需要调用 [pool drain]来销毁自动释放池。
自动释放池中不适宜放占用内存较大的对象或大量循环操作。
6. 循环retain
当A对象要拥有B对象,同时B对象要拥有A对象,此时会形成循环retain,导致A和B对象永远无法释放。
尽量避免双端互相引用,或者一端用retain,一端用assign。
五. ARC – 自动引用计数
1. ARC
自动引用计数,系统检测出何时需要保持对象,何时需要自动释放对象,编译器会管理内存,并在合适的地方加入retain,release和autorelease。
2. ARC的判断原则 – 强指针
ARC通过强指针判断一个对象是否需要释放。
默认所有对象的指针变量都是强指针,或者被“__strong”修饰的指针。
被**__weak修饰的指针是弱指针**。
只要还有一个强指针变量指向对象,对象就会保持在内存中。
3. ARC的注意事项
- 不能调用对象的release方法。
- 不能调用autorelease方法。
- 重写dealloc方法时,不能调用**[super dealloc]**。
4. 单对象内存管理
局部变量(局部强指针)超出作用域释放,对象随之被释放。
清空指针(默认清空的所有指针都是强指针),对象随之被释放。
弱指针保存新创建的对象时,对象会立即被释放。
5. 多对象内存管理
- 想要拥有某个对象必须使用强指针保存它,无需在dealloc方法中release。
6. property参数
- strong:用于OC对象,相当于MRC中的retain。
- weak:用于OC对象,相当于MRC中的assign。
- assign:用于基本数据类型,与MRC中的assign相同。
7. 循环引用
如果A拥有B,B也拥有A,那么其中一方必须使用弱指针。