一、内存管理机制——引用计数
1、什么是内存管理
移动设备的内存极其有限,每个app所能占用的内存是有限制的。当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间。比如回收一些不需要使用的对象、变量等。管理范围:任何继承了NSObject的对象,对其他基本数据类型(int、char、float、double、struct、enum等)无效
2、引用计数:引用计数的数值表示有几个其它对象在使用它。
每一个对象都拥有一个引用计数:
当对象被创建的时候,引用计数的值为1
当给对象发送retainCount消息获得当前的引用计数器值
当发送retain消息的时候,该对象的引用计数加1,该对象的引用计数为2(retain方法返回对象本身)
当这个对象发送release消息的时候,该对象的引用计数减1
当一个对象的引用计数为0时,系统自动调用dealloc方法,销毁该对象。
- Dog *dog = [[Dog alloc]init];//此时引用计数为1
- NSLog(@" %d",[dog retainCount]);
- [dog retain];//引用计数变成2
- [dog release];//引用计数变成1
- [dog release];//引用计数变成0,系统会自动调用dealloc方法,销毁对象,回收内存
引用计数是实例对象的内存回收唯一参考
3、引用计数(retainCount)是Objective-C管理对象引用的唯一依据。调用实例的release方法后,此属性减一,减到为零时对象的dealloc方法被自动调用,进行内存回收操作,也就是说我们不能手动调用对象的dealloc方法。对于dealloc方法
它的作用是,当对象的引用计数为0时,系统会自动调用dealloc方法,回收内存,它的一般写法为:
-(void)dealloc -(void)dealloc
{ {
[super dealloc]; [personrelease];
} [super dealloc];
}
对象的销毁应该注意:
(1)当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收
(2)当一个对象被销毁时,系统会自动向对象发送一条dealloc消息
(3)一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言
(4)一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用
(5)不要直接调用dealloc方法
(6)一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)
4、对象所有权
当一个所有者(可以是任何一个OC对象)做了以下某个动作的时候,它就拥有了对一个对象的所有权。
(1)如果创建或者复制某个对象时,则拥有了该对象的所有权,即包含下列关键词时:alloc,allocWithZone:,copy,copyWithZone:,mutableCopy,mutableCopyWithZone:
(2)如果没有创建或复制对象,而是保留引用,同样拥有该对象的使用权retain
(3)当拥有了某个对象的所有权,在不需要某一个对象时,需要释放他们,用release,autoRelease
5、引用计数器的作用
(1)当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1
(2)当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收。换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收,除非整个程序已经退出
6、set方法的内存管理
如果你有个OC对象类型的成员变量,就必须管理这个成员变量的内存。比如有个Book *_book
set方法的实现:
- (void)setBook:(Book *)book{
if(book != _book) {
[_bookrelease];
_book= [book retain];
}
}
dealloc方法的实现:
- (void)dealloc {
[_bookrelease];
[superdealloc];
}
二、自动释放池的相关用法
1、自动释放池(Autorelease pool),是能够自动释放赤忠的对象的。NSObject类提供了一个autorelease消息,当我们想一个对象发送autorelease消息的时候,这个对象就会随着释放池的销毁而释放。如果要向使用使用自动释放池释放对象,我们首先要有一个入池操作:
- //创建自动释放池
- @autoreleasepool {
- //入池对象5.0之后的写法
- }
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
- //入池对象5.0之前写法
- [pool release];
自动释放池是以栈的形式实现的,当某个对象调用了autorelease方法时,该对象会被加入自动释放池的栈顶。对于发送了autorelease消息的对象,当自动释放池销毁时,自动释放池会对这些对象发送一条release消息,来释放他们。
2、autorelease
(1)给某个对象发送一条autorelease消息时,就会将这个对象加到一个自动释放池中
(2)当自动释放池销毁时,会给池子里面的所有对象发送一条release消息
(3)调用autorelease方法时并不会改变对象的计数器,并且会返回对象本身
(4)autorelease实际上只是把对release的调用延迟了,对于每一次autorelease,系统只是把该对象放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有对象会被调用Release
3、向自动释放池发送release及drain消息的区别
当我们向自动释放池pool发送release消息时,它会向池中的每一个发送了autorelease消息的对象发送一条release消息,并且自身也会销毁。当向它发送drain消息时,只会释放里面吧的对象,而不会销毁自己。