内存管理 :
主要对堆内存进行管理,所谓的管理是指内存的分配(创建)和释放(回收)
内存管理:管理对象的分配和释放,回收那些不需要再使用的对象(内存)
下列行为都会增加一个app的内存占用
- 创建一个OC对象
- 定义一个变量
- 调用一个函数或者方法
如果app占用内存过大,系统可能会强制关闭app,造成闪退现象,影响用户体验
1.1 两种管理方式
MRC(Manual Reference Counting):手动引用计数(手动管理内存)
所有对象的内存都需要我们手动管理, 需要程序员自己编写retain/release等代码
ARC(Automatic Reference Counting):自动引用计数(自动管理内存)
不需要程序员管理内存,编译器会在适当的地方自动给我们添加retain/release等代码
注意点: OC中的ARC和java中的垃圾回收机制不太一样,java中的垃圾回收是系统干得,而OC中的ARC是编译器干得
1.2 引用计数器(Reference Counting)
- 每个对象都有自己的引用计数器,引用计数器是用来计算对象被引用的次数。
- 发送消息时(alloc、copy、new),将引用计数器置为1。
- OC语言使用对象的引用计数来管理内存。一个对象只要有另一个对象指向它,引用计数就得+1,当另一个对象不指向它时,引用计数就-1,当引用计数减成0时,说明这个对象已经没有人用了,系统会将对象的内存空间释放掉。
MRC是指对象的引用计数的加减操作手动进行,意思就是由程序员写代码来完成。
ARC是指对象的引用计数的加减操作自动进行,意思是说不需要程序员写代码,而是由编译器自动生成代码完成。
1.3 MRC下的引用计数器的操作
1)引用计数器加1(retain)
当你需要使用一个别人创建好的对象时,为了防止在使用此对象期间别人释放了这个对象,我们要将此对象的引用计数器加1(程序员通知引用计数器),只要给对象发送retain消息,引用计数器就会加1。
2)引用计数器减1(release)
- 当你使用的对象不再使用时,发送release消息
- release消息将对象的引用计数器减1
- 如果引用计数器为0,则释放对象所占的存储空间。
3)dealloc与对象销毁
- 当对象的引用计数器为0时,说明已经没有任何引用指向对象,对象就会被系统自动销毁。
- 系统销毁对象之前,会自动向对象发送一条消息”dealloc”消息,对象所占的空间就会被释放,千万不要自己去调用dealloc消息。
- 可以使用“retainCount消息”,查看当期引用计数器的值。
NSLog(@“引用.retainCount = %ld”, 引用.retainCount); //打印引用计数器的值
1.4 dealloc方法
当一个对象的引用计数器值为0时(对象即将被销毁时),系统就会自动调用dealloc方法。
因此,从dealloc方法有没有被调用,就可以判断出对象是否被销毁
一般通过dealloc方法来监听一个对象有没有被释放,而不用retainCount方法(retainCount方法有时候不是很准确)
- dealloc方法的重写
- 一般会重写dealloc方法,在这里释放相关资源,dealloc就是对象的遗言
- 一旦重写了dealloc方法,就必须要在最后面调用 [super dealloc] (ARC下,不能调用父类的方法dealloc)
- 使用注意
- 不能手动调用dealloc方法,由系统自动调用
- 一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)
1.5 野指针与空指针:
僵尸对象:已经被销毁的对象(不能在使用的对象)
野指针
- 指向僵尸对象(不可用内存)的指针
- 给野指针发消息会报EXC_BAD_ACCESS错误
空指针:
- 没有指向存储空间的指针(里面存的是nil,也就是0)
- 给空指针发消息是没有任何反应的
- 为了避免野指针错误的常见办法。在对象被销毁之后,将指向对象的指针变为空指针。
只要一个对象被释放了,我们就称这个对象为"僵尸对象"
当一个指针指向一个僵尸对象,我们就称这个指针为野指针,只要给一个野指针发送消息就会报错。
监听"僵尸对象"的报错(方便调试,会在控制台输出错因):
注意:null.name和[null run]; 不能用null去访问属性和调用方法。虽然不会报错,但是什么也不会发生。
OC是弱语法语言,有些错误编译不会报错!
1.6 内存管理原则
苹果官方规定的内存管理原则:
- 谁创建谁release:
如果你通过alloc、new或copy来创建一个对象,那么你必须调用release或autorelease
- 谁retain谁release:
只要你调用了retain,就必须调用一次release
总结:
- 有加就有减
- 曾经让对象的计数器+1,就必须在最后让计数器-1
1.7 MRC项目与ARC项目之间的转换
创建的项目默认使用ARC。
- ARC —> MRC:
如果要使用MRC,要么将某个需要使用MRC的.m文件设置成MRC,或将整个项目变成MRC。
1) 如何将单个.m文件设置成MRC/ARC:
在Xcode中选中项目-》Build Phases-》Compile Sources-》选中需要使用MRC的.m文件-》双击此文件。
在弹出地小窗口中输入以下内容:
-fno-objc-arc (设置MRC:表示文件不支持Objective-C的ARC)
-fobjc-arc (设置ARC:表示文件支持Objective-C的ARC)
2) 如何将整个项目改成MRC:
在Xcode中选中项目==>Build Settings==>搜索"Automatic Reference ( ARC ) ”==>找到"Objective-C Automatic Reference Counting"将其值"YES"改成NO. 意思是关闭ARC,此时项目就全是MRC了
- MRC —> ARC:
Xcode菜单:Edit —>Convert —> To Objective-C ARC…
如何让代码既兼容ARC又兼容MRC?
//MRC时 #if(!__has_feature(objc_arc)) //MRC下的执行代码 #endif |
//ARC时 #if __has_feature(objc_arc) //ARC下的执行代码 #else //MRC下的执行代码 #endif |