holydancer原创,如需转载,请在显要位置注明:
转自holydancer的CSDN专栏,原文地址:http://blog.csdn.net/holydancer/article/details/7350318
objective c中的内存管理是很让人纠结的,如果程序从头到尾没有遇到内存泄漏或者别的内存问题倒也罢,如果一旦内存上出现了问题,那排起错来真是要人命啊,今天笔者大致介绍一下内存的实现原理,希望能在将来碰到内存问题时能够有些头绪。
我们都知道每个类在创造实例时都会在内存中给它划分一片区域用来存放信息,然后对象名作为指针指向该内存空间,如果这个对象不用了,那么这片内存区域就会被系统回收,抹掉内容或者覆盖上别的内容,objective c中没有java中那么强大的垃圾回收机制,网上有人称其为半自动模式,相当形象。那么我们通过什么来判断这个内存空间是否仍在使用呢,这里就需要引入一个概念:“引用计数(reference couting)”.当该对象创建时,该计数为1,说明有一个引用,如果不用时,就会减为0,这就表示不再使用了,那么就会销毁该空间。
引用计数会在使用new,alloc,copy创建对象时,会自动将引用计数设为1,可以通过retainCount来查看,如下:
#import <Foundation/Foundation.h>
@interface Man:NSObject
-(void)say;
@end
@implementation Man
-(void)say
{
NSLog(@"man say");
}
@end
int main(int argc, const char * argv[])
{
Man *man1=[Man new];
NSLog(@"%lu",[man1 retainCount]);
[man1 release];
return 0;
}
2012-03-13 20:14:38.559 retain[2906:403] 1
当不再使用该对象时,要用release方法将该内存释放。
当不是用以上介绍的三种方法创建对象的话,我们不需要使用release方法手动释放,但是其计数仍为1,只是系统会自动释放。有的时候我们会长久使用一些对象,比如某些对象本身作为别的对象的参数之类又或者将其加入数组之类的,我们需要手动增加一个计数,retain一下,需要注意的是每retain一次,都要对应的有一个release,具体retain多少次,什么时候释放需要看代码环境,但是这个原则是肯定的,每retain一次,就要release释放一次。下面看一部分代码来理顺一下思路 :
#import <Foundation/Foundation.h>
@interface Man:NSObject
-(void)say;
@end
@implementation Man
-(void)say
{
NSLog(@"man say");
}
@end
int main(int argc, const char * argv[])
{
Man *man =[Man new];//生成一个新对象man,引用计数为1
NSLog(@"%lu",[man retainCount]);//
[man retain];//手动增加一个引用计数用以保留man对象,引用计数为2
NSLog(@"%lu",[man retainCount]);
[man release];//手动释放一个引用计数,现在count为1
NSLog(@"%lu",[man retainCount]);
[man release];//再释放一个,这时man对象的内存已经被抹掉了
//[man say];如果这个方法不注释的话就会报错。
NSLog(@"%lu",[man retainCount]);
//这里之所以还为1,是因为这里是以man方法调用的,所以这里又生成了一个不知名的对象,但是这个对象中并没有
//say方法了,但是因为这里重新用man引用了这片内存,所以计数仍为1.
return 0;
}
2012-03-13 20:34:44.440 String[3870:403] 1
2012-03-13 20:34:44.443 String[3870:403] 2
2012-03-13 20:34:44.444 String[3870:403] 1
2012-03-13 20:34:44.445 String[3870:403] 1
另外,objective c中引入了autorelease 和autorelease pool(自动释放对象池)的概念,可以自动释放对象。
Man *man =[[Man new] autorelease];这时就不用再释放。
自动释放池可以手动创建:
#import <Foundation/Foundation.h>
@interface Man:NSObject
-(void)say;
@end
@implementation Man
-(void)say
{
NSLog(@"man say");
}
@end
int main(int argc, const char * argv[])
{
NSAutoreleasePool *pool;
pool =[[NSAutoreleasePool alloc] init];
Man *man1;
Man *man2;
//可以将好好多对象放入一个自动释放池;
[man1 autorelease];
[man2 autorelease];
//然后可以一下子释放池里所有的对象;
[pool release];//相当于对池中每个对象执行了一次release;
}
一般情况下,只要在有new,alloc,copy出现后,记得要release,在手动retain后,记得也肯定会有release,并且retain和release是对应在一个对象身上,这样就不会出现问题。额,先这样吧,等什么时候有补充我再作更改,憋不住了,上厕所去。