一 基本原理
Objective-C的内存管理机制与Java那种全自动的垃圾回收机制是不同的,它本质上还是C语言中的手动管理方式,只不过稍加了一些自动方法.
1,OC采用了引用计数(retain count)对对象内存进行管理,例如,某个对象alloc了,那么这个对象的引用计数就加1,retain时加1,当对象不需要用时就需要销毁对象,释放内存,需要对象调用release方法,release会让引用计数减1,只有引用计数消失,相当于等于0,对象才会调用dealloc真正销毁这个对象.
OC的对象在使用完成后不能自动销毁,一定要记得释放内存.
Class *obj = [[Class alloc]init];//对象obj引用计数加1
Class *obj2 = obj;//两个对象指向同一块内存
[obj hello];
[obj release];//对象被销毁
[obj2 hello];//错误,obj2指向的内存不存在了
[obj2 release];//[obj release]之后,obj2是个无效指针,没有内存,不能调用方法.
注:dealloc是自动调用,一定不能手动调用.指针赋值不会使引用计数加1.
2,OC中引入了autorelease pool(自动释放对象池),在遵守一些规则的情况下,可以自动释放对象.新生成的对象,只要调用autorelease就行了,无需再调用release.
autorelease pool需要手动建立,在新建一个项目时,xcode会自动创建一个,NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];NSAutoreleasePool 内部包含一个数组(NSMutableArray),用来保存声明为autorelease的所有对象,一个对象声明为autorelease,系统所做的工作就是把这个对象加入到这个数组中去.
NSAutoreleasePool自身在销毁的时候,会遍历一遍这个数组,release数组中的每一个成员.如果此时数组中成员的retain count为1那么release之后,retain count为0,对象正式销毁,如果此时数组中成员的retain count大于1,那么release之后,retain count大于0,对象依然没有被销毁,内存就会泄露,所以一定要注意内存管理规则(见下).
注:什么情况下创建自动释放对象池?1)在多线程里面要自己创建.2)如果代码里面有大量临时变量时最好创建自动释放对象池.
for(int i=0;i<100;i++){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for(int j=0;j<100000;j++){
[NSString stringWithFormat:@"123455666"];//产生的对象是autorelease的.
}
[pool release];
}
二、规则
1 谁创建,谁释放。如果通过alloc、new或copy来创建一个对象,那么你必须调用autorelease或在使用完成时调用release,不是你创建的,就不用你去释放。
2 除了alloc,new或copy之外的方法创建的对象在内部都被声明了autorelease。如,[UIButton buttonWithType:].
3 谁retain,谁release,只要你调用了retain,无论这个对象是如何生成的,你都要调用release.
三、范式
1 创建一个对象
Class *obj = [[Class alloc] init];
2 创建一个自动释放对象
Class *obj = [[[Class alloc] init]autorelease];
3 指针赋值给另一个指针
Class *obj2 = obj1;
[obj2 retain];
[obj2 release];
4 在一个函数中创建并返回对象,需要把这个对象设置为autorelease
- (Class *)fun{
Class *obj = [[[Class alloc] init] autorelease];
return obj;
}
5 在子类的dealloc方法中调用基类的dealloc方法
- (void)dealloc{
……
[super dealloc];
}
对于属性里的内存机制请参考属性详细说明。
注:不要过度依赖retaincount,有时候内部实现并不像表面那样,计数不会换我们看到的那样,例如
MovieViewController *movie = [[MovieViewController alloc]init];
NSLog(@"===%d",[movie.view retainCount]);//3
NSLog(@"===%d",[movie.view retainCount]);//4
NSLog(@"===%d",[movie.view retainCount]);//5