Objective-C 学习笔记(2) -- OC的内存管理

来源:互联网 发布:asp在线考试系统源码 编辑:程序博客网 时间:2024/05/11 18:20

1.引用计数(保留计数):OC使用计数值对内存进行管理。

(1)首先,使用alloc在堆上生成对象。使用dealloc将对象所分配的内存释放。

(2)当使用alloc或者new或copy构造对象的时候,对象的保留计数值被置为1。

(3)要增加对象的保留计数器值,可以给对象发送一个retain消息,如果要减少计数值,则给对象发送release消息。

(4)当对象的计数值为0的时候,dealloc自动被调用。

(5)使用 -(unsigned)retaincount 返回当前的计数值。

 

2.内存泄露和指针无效:

(1)考虑以下代码:

classA *obj1 = [[classA alloc] init];

classA *obj2 = obj1;

[obj1 dealloc];

[obj2 dealloc];

这段代码执行会出现错误。原因是因为obj1和obj2都指向内存中的classA对象的实例,那么在第三行dealloc被调用后,第四行就无效了。

实际上,在OC中,一般使用release做引用计数的减少,当count=0的时候,析构会自动被调用。

 

(2)将(1)中的代码作以下改动:

classA *obj1 = [[classA alloc] init];

classA *obj2 = obj1;

[obj1 release];

[obj2 release];

这段代码也有问题。在obj1调用release后,count = 0,那么dealloc自动被调用。正确的处理是:

classA *obj1 = [[classA alloc] init];

classA *obj2 = obj1;

[obj2 retain]; //将引用计数值加1

[obj1 release];

[obj2 release];

 

(3)set方法中传递对象的写法:

-(void)setA:(A*) newA

{

      [newA retain];

      [a release];

      a = newA;

}

解释一下。在这里,newA指向外部传入的参数。首先因为有指针的赋值,因此引用计数需要加1,然后旧的a需要将引用计数值减少(此时旧的A指向的外部对象有可能因为count=0而自动调用dealloc释放,这里保证了内存不会泄露),再将旧a指向新的外部对象。这样即便是外部传入的newA对象在主函数的操作中执行了release操作,函数中的a指向的对象仍然会存在。

 

(4)AutoreleasePool

NSAutoReleasePool *pool = [[NSAutoreeleasePool alloc] init];

在该pool中,有一个NSMutableArray的对象用于保存所有声明为autorelease的对象。当对象被声明为AutoRelease的时候,则不需要再调用release,因为在NSAutoreleasePool销毁的时候,会遍历一遍数组,以release数组中的每个成员。此时若数组中成员的retaincount为1,则OK,若>1则出现内存泄露。

 

(5)在程序中,autorelease被标记的越多,则程序越容易丧失性能。解决办法是生命局部的pool,例如:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

int i,j;

for(i=0;i<=10;i++)

{

     NSAutoreleasePool *temppool = [[NSAutoreleasePool alloc] init];

     for(j=0;j<=10000;j++)

    {

        [NSString stringwithformat:@"123456789"];

    }

    [temppool  release];

}

[pool release];

 

(6)返回自动销毁的对象,例如:

-(NSString *) des:(int) n

{

     NSString *description;

     description = [[NSString alloc] initWithFormat:@"hello! %d",n];

     return ([description autorelease]);

}

 

3. 单例模式

@implementation Singleton

 

+(Singleton *)getInstance

{

      staticSingleton *instance;

      @synchronized(self){

           if(!instance)  instance = [[Singleton alloc] init];

      }

      return (instance);

}

 

@end

 

对于该单例,可以使用 [Singleton getInstance]得到。