内存管理
ARC: Automatic(自动) Reference(引用) Counting(计数)
什么是自动引用计数?
不需要程序员管理内容, 编译器会在适当的地方自动给我们添加release/retain等代码
注意点: OC中的ARC和java中的垃圾回收机制不太一样, java中的垃圾回收是系统干得, 而OC中的ARC是编译器干得
MRC: Manul(手动) Reference(引用) Counting(计数)
什么是手动引用计数?
所有对象的内容都需要我们手动管理, 需要程序员自己编写release/retain等代码
内存管理的原则就是有加就有减
也就是说, 一次alloc对应一次release, 一次retain对应一次relese
野指针和空指针
只要一个对象被释放了, 我们就称这个对象为 "僵尸对象"
当一个指针指向一个僵尸对象, 我们就称这个指针为野指针
只要给一个野指针发送消息就会报错
// *** -[Person release]: message sent to deallocated instance 0x1001146b0
空指针 nil 0
为了避免给野指针发送消息会报错, 一般情况下, 当一个对象被释放后我们会将这个对象的指针设置为空指针
因为在OC中给空指针发送消息是不会报错的
MRC
1. 【掌握】内存管理原则
2. 【掌握】多对象内存管理
3. 【掌握】set方法内存管理
4. 【掌握】dealloc方法的内存管理
1.内存管理原则
- 苹果官方规定的内存管理原则
+ 谁创建谁release :
* 如果你通过alloc、new、copy或mutableCopy来创建一个对象,那么你必须调用release或autorelease
+ 谁retain谁release:
* 只要你调用了retain,就必须调用一次release
- 总结一下就是
+ 有加就有减
+ 曾经让对象的计数器+1,就必须在最后让对象计数器-1
---
2.多对象内存管理
- 单个对象的内存管理, 看起来非常简单
- 如果对多个对象进行内存管理, 并且对象之间是有联系的, 那么管理就会变得比较复杂
- 其实, 多个对象的管理思路 跟很多游戏的房间管理差不多
+ 比如斗地主 劲舞团 QQ音速
![](images/a5/534347_001415_6_lit.jpg)
- 总的来说, 有这么几点管理规律
+ 只要还有人在用某个对象,那么这个对象就不会被回收
+ 只要你想用这个对象,就让对象的计数器+1
+ 当你不再使用这个对象时,就让对象的计数器-1
3.set方法内存管理
- (1)retain需要使用的对象
- (2)release之前的对象
- (3)只有传入的对象和之前的不同才需要release和retain
- (void)setRoom:(Room *)room
{
// 避免过度释放
if (room != _room)
{
// 对当前正在使用的房间(旧房间)做一次release
[_room release];
// 对新房间做一次retain操作
_room = [room retain];
}
}
4.dealloc方法的内存管理
- (void)dealloc
{
// 当人不在了,代表不用房间了
// 对房间做一次release操作
[_room release];
[super dealloc];
}
ARC
ARC机制下有几个明显的标志:
+ 不允许调用对象的 release方法
+ 不允许调用 autorelease方法
+ 再重写父类的dealloc方法时,不能再调用 [super dealloc];
ARC下单对象内存管理
- 局部变量释放对象随之被释放
默认情况所有指针都是强指针
弱指针需要明确说明
+ 注意: 千万不要使用弱指针保存新创建的对象
.ARC下多对象内存管理
- ARC和MRC一样, 想拥有某个对象必须用强指针保存对象, 但是不需要在dealloc方法中release
.ARC下循环引用问题
- ARC和MRC一样, 如果A拥有B, B也拥有A, 那么必须一方使用弱指针
ARC下@property参数
- strong : 用于OC对象, 相当于MRC中的retain
- weak : 用于OC对象, 相当于MRC中的assign
- assign : 用于基本数据类型, 跟MRC中的assign一样
问题1:什么是堆?什么是栈?
答:
- 栈(操作系统):由操作系统自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈(先进后出);
- 堆(操作系统):一般由程序员分配释放,若程序员不释放,程序结束时可能由系统回收,分配方式类似于链表。
问题2:什么是内存管理?
答: 所谓内存管理, 就是对内存进行管理, 涉及的操作有:
- 分配内存 : 比如创建一个对象, 会增加内存占用
- 清除内存 : 比如销毁一个对象, 能减小内存占用
问题3:内存管理的本质是什么?
答:
- OC对象存放于堆里面
- 非OC对象一般放在栈里面(栈内存会被系统自动回收)
2.引用计数器和dealloc基本概念
问题1:什么是引用计数器?
答:每个OC对象都有自己的引用计数器,它是一个整数,表示有多少人正在用这个对象
问题2:引用计数器的作用?
答:
- 当使用alloc、new或者copy创建一个对象时,对象的引用计数器默认就是1
- 当对象的引用计数器为0时,对象占用的内存就会被系统回收
- 如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收(除非整个程序已经退出 )
问题3:怎么操作引用计数器?
答:
- 给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身
- 给对象发送一条release消息, 可以使引用计数器值-1
- 给对象发送retainCount消息, 可以获得当前的引用计数器值
- 需要注意的是: release并不代表销毁回收对象, 仅仅是计数器-1
问题4:dealloc 方法的作用?
答:
- 对象即将被销毁时系统会自动给对象发送一条dealloc消息
- (因此, 从dealloc方法有没有被调用,就可以判断出对象是否被销毁)
3.单个对象内存管理
问题1:什么是ARC?什么是MRC?
答:
1.ARC: Automatic(自动) Reference(引用) Counting(计数)
什么是自动引用计数?
不需要程序员管理内容,编译器会在适当的地方自动给我们添加release/retain等代码
- 注意点: OC中的ARC和java中的垃圾回收机制不太一样, java中的垃圾回收是系统干得, 而OC中的ARC是编译器干得
2.MRC: Manul(手动) Reference(引用) Counting(计数)
什么是手动引用计数?
所有对象的内容都需要我们手动管理, 需要程序员自己编写release/retain等代码
问题2:重写dealloc方法有什么注意点?
答: 重写dealloc方法, [super dealloc]一定要写到所有代码的最后
4.野指针和空指针
问题1:什么是僵尸对象?什么是野指针?什么是空指针?如何避免野指针错误?
答:
1. 僵尸对象 已经被销毁的对象(不能再使用的对象)
2.野指针 指向僵尸对象(不可用内存)的指针 给野指针发消息会报EXC_BAD_ACCESS错误
3.空指针 没有指向存储空间的指针(里面存的是nil, 也就是0) 给空指针发消息是没有任何反应的
4. 为了避免野指针错误的常见办法: 在对象被销毁之后, 将指向对象的指针变为空指针
5.多对象内存管理
问题:内存管理的原则?
答:
1.谁创建谁release
如果你通过alloc、new、copy或mutableCopy来创建一个对象,那么你必须调用release或autorelease
2.谁retain谁release:
只要你调用了retain,就必须调用一次release
3.总结:
有加就有减,曾经让对象的计数器+1,就必须在最后让对象的计数器-1
1.autorelease基本概念
问题1:什么是自动释放池?
答: autorelease是一种支持引用计数的内存管理方式,只要给对象发送一条autorelease消息,会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
问题2:自动释放池的优点是什么?
答:
- 不用再关心对象释放的时间
- 不用再关心什么时候调用release
问题3:简述自动释放池的原理?
答: autorelease实际上只是把对release的调用延迟了,对于每一个autorelease,系统只是把该 Object放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有Object会被调用release。
问题4:如何使用自动释放池?(用代码书写)
答:
基本使用
1)方法一:
NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init];
Person *p = [[[Person alloc] init] autorelease];
[autoreleasePool release];
2)方法二:
@autoreleasepool
{
// 创建一个自动释放池
Person *p = [[[Person alloc]init]
autorelease];
} // 销毁自动释放池(会给池子中所有对象发送一条release消息)
2.自动释放池注意事项
问题1:自动释放池有哪些注意事项?
答:
- 在自动释放池中创建了对象, 一定要调用autorelease,才会将对象放入自动释放池中
- 一个程序中可以创建N个自动释放池, 并且自动释放池还可以嵌套
- 不要再自动释放池中使用比较消耗内存的对象, 占用内存比较大的对象
- 尽量不要再自动释放池中使用循环, 特别是循环的次数非常多, 并且还非常占用内存
- 千万不要写多次autorelease
- 一个alloc/new对应一个autorelease或者release
问题2:自动释放池是以什么形式存储的?
答:
- 如果存在多个自动释放池的时候, 自动释放池是以 "栈" 的形式存储在堆区
- 栈的特点: 先进后出
问题1:ARC的原理是什么?
答: 当ARC开启时,编译器将自动在代码合适的地方插入retain, release和autorelease,而作为程序猿,完全不需要担心编译器会做错(除非开发者自己错用ARC了)。
问题2:ARC有什么优点?
答:
- 完全消除了手动管理内存的烦琐, 让程序猿更加专注于app的业务
- 基本上能够避免内存泄露
- 有时还能更加快速,因为编译器还可以执行某些优化
问题3:ARC的原则是什么?什么是强指针?什么是弱指针?
答: 只要还有一个强指针变量指向对象,对象就会保持在内存中
1.强指针
- 默认所有指针变量都是强指针
- 被__strong修饰的指针
例如:
Person *p1 = [[Person alloc] init];
__strong Person *p2 = [[Person alloc] init];
2.弱指针
- 被__weak修饰的指针
- __weak Person *p = [[Person alloc] init];
4.ARC基本概念
问题1:ARC下@property修饰符有哪些?
答:
- strong : 用于OC对象, 相当于MRC中的retain
- weak : 用于OC对象, 相当于MRC中的assign
- assign : 用于基本数据类型, 跟MRC中的assign一样
问题2:ARC中是怎么对对象进行内存管理的?
答:
1.ARC下单对象内存管理
1)ARC下,所有的指针都是强指针
2)ARC, A对象想拥有B对象, 那么就需要用一个强指针指向B对象
3)A对象不用B对象了, 什么都不需要做, 编译器会自动帮我们做
2.ARC下多对象内存管理(strong ,weak, assign)
//
在ARC中保存一个对象用strong, 相当于MRC中的retain
@property(nonatomic, strong)Dog *dog;
//
在ARC中如果保存对象不要用assign, 用weak
// assign是专门用于保存基本数据类型的, 如果保存对象用weak
@property(nonatomic, weak)Person *owner;
问题3:ARC怎么解决循环引用问题?
答:
- ARC和MRC一样, 如果A拥有B, B也拥有A, 那么必须一方使用弱指针
- 也就是说 一端用strong ,一端用weak
6.ARM和MRC混编
问题1:ARC模式下如何兼容非ARC的类?
答:
找到project->targets->Bulid Phases->Compiles Sources->找到相关文件右击右边Compiler Flags添加相关代码
给相关文件添加一端代码,
- 转变为非ARC -fno-objc-arc
- 转变为ARC的, -f-objc-arc (不常用)
7.MRC转ARC
问题1:如何操作Xcode将MRC转ARC?
答:Edit->Convert->To Objective ARC