OC的内存管理以及MRC与ARC
内存中的五大区域:
栈区,堆区,BBS段,数据段和代码段,其中除了堆区以外,其他区域的内存管理由系统自行回收
OC对象是存储在堆区的,所以OC的内存管理主要是对”堆区中的OC对象”进行管理
内存管理中的几个概念:
->引用计算器:既retainCount,每个OC对象内部都有1个8字节空间用来存储retainCount,表示有多少”人”正在使用;
对象刚被创建时,默认计数值就为1,当计数值为0时,系统会自动调用dealloc方法将对象销毁
引用计数器的用法:给对象发送相应的技术操作来改变计数器的值
retain消息:使计数器+1
release消息:使计数器-1
retainCount消息:得到当前当前retainCount的值
->野指针:没有初始化的指针变量
->僵尸对象:指一个对象已经被回收,但其数据还存在内存中
僵尸对象有可能可以访问,也有可能不能访问,取决于所占用空间是否已被重新分配.然而,对象一旦被回收就不该再被访问,此时可以开启僵尸对象检测,这样系统会自动检查是否为僵尸对象,但同时也会降低执行效率.
->内存泄露:指对象没有在该回收的时候被回收,而是一直驻留在内存中,直到程序结束的时候才被释放
内存管理的分类:
->MRC:Manual Reference Counting,既手动内存管理
对引用计数器的操作全由程序员亲自完成
->ARC:Automatic Reference Counting,既自动内存管理
(垃圾回收不能在iOS系统使用,故此处暂不讨论)
系统会依照程序员的要求自动改变引用计数器的值(Xcode6开始,默认使用ARC)
手动内存管理:
->手动内存管理的原则:
1)一旦创建一个对象,这个对象的引用计数器的值就为1,所以必须要匹配1个release
2)只有在多1个人使用这个对象的时候才retain
只有在烧1个人使用这个对象的时候才release
3)retain的次数要和release次数相匹配
4)永远不要手动调用对象的dealloc方法,而是让系统自动调用
->手动内存管理中内存泄露的几种情况:
1) retain和release不匹配,retain多余release导致的内存泄露;
2) 对象使用过程中,没有被release,而被赋值为nil;
3) 在方法中不当的使用了retain;
手动内存管理的关键就是防止内存泄露!!!!!防止内存泄露要记住:
1) 谁创建”alloc","new",谁"release";
2) 谁”retain",谁"release";
->多对象的手动内存管理:
当B类作为A类属性时,要防止内存泄露,则A类的setter方法应为:
其中setter方法实现还可写成:
以上是标准的MRC内存管理代码.
->循环retain问题:
1) 遇到的问题:
当两个对象相互引用的时候.
A对象的属性指向B对象, B对象的属性指向A对象.
这个时候,如果两边都使用retain.就会出现内存泄露. 都回收不了.
2) 解决方案:
1端使用retain,1端使用assign.(请查看@property带参数用法的相关内容)
需要注意的是: 使用assign的那1段,dealloc中不需要再去release这个对象了.
->自动释放池(autorelease)
1)原理:
存储在自动释放池的对象,在自动释放池销毁时,会自动调用该对象的release方法,故将对象存储在自动释放池中,就不需要再写release
2)创建方法:
@autorelease
{
} //大括弧表示自动释放池的范围
3)将对象放入的方法:
在自动释放池的范围中调用对象的autorelease方法.注:autorelease的返回值是对象本身,所以我们可以这样创建对象:
@autorelease
{
类型 *对象 = [类名 alloc] init] autorelease];
}
4)使用注意:
a.只有在自动释放池中调用了对象的autorelease方法,这个对象才会被存储到这个自动释放池之中
b. 对象的创建可以在自动释放池的外面,在自动释放池之中,调用对象的autorelease方法,就可以将这个对象存储到这个自动释放池之中.
c. 当自动释放池结束的时候.仅仅是对存储在自动释放池中的对象发送1条release消息 而不是销毁对象.
d. 如果在自动释放池中,调用同1个对象的autorelease方法多次.就会将对象存储多次到自动释放池之中.在自动释放池结束的时候.会为对象发送多条release消息.那么这个时候就会出现僵尸对象错误.
e. 自动释放池可以嵌套.调用对象的autorelease方法,会讲对象加入到当前自动释放池之中,只有在当前自动释放池结束的时候才会像对象发送release消息.
5)使用规范:
我们一般情况下,写1个类.会为我们的类写1个同名的类方法,用来让外界调用类方法来快速的得到1个对象.应遵守规范:使用类方法创建的对象,要求这个对象在方法中就已经被autorelease过了.这样,我们只要在自动释放池中, 调用类方法来创建对象, 那么创建的对象就会被自动的加入到自动释放中.
自动内存管理:
->自动内存管理原则: 编译器会自动的在合适的地方插入retain、release、autorelase代码;编译器自动为对象做引用计数. 而作为开发者,完全不需要担心编译器会做错(除非开发者自己错用了ARC).
->强指针与弱指针:
强指针:默认情况下,我们声明的指针都为强指针,也可以使用__strong来显示的声明指针为强指针.
弱指针:使用__weak关键字修饰的指针,例如 __weak Person *p;
作用与区别:在ARC模式下,强指针与弱指针用来作为回收对象的标准,当1个对象即使用弱指针指向,但没有任何强指针指向时就会被立即回收,此时该弱指针会被自动设置为nil.
->ARC模式下的循环引用:
在ARC机制下,如果出现了循环引用,既A对象中有1个属性是B对象. B对象中有1个属性是A对象.此时如果两边都为strong.就会发生内存泄露.
解决方案:1端使用strong 另外1端使用weak
MRC和ARC的转换与兼容:
# ARC兼容MRC的类
target --> Build Phaese ---> Compiler Sources --> Compiler Flags
让程序兼容ARC和非ARC部分。
转变为非ARC -fno-objc-arc
转变为ARC的, -f-objc-arc
# MRC转ARC
Xcode —> refactor --> Convert to Objective-C ARC 选中要装换的target --> 调校代码