内存管理详解

来源:互联网 发布:懒人图库js 编辑:程序博客网 时间:2024/05/04 21:25

内存管理详解


Objective-c 提供了三种内存管理方式:manual retain-release (MRR 手动管理),automatic  reference counting (ARC, 自动引用计数),garbage collection(垃圾回收)。 iOS 不支持垃圾回收;ARC作为苹果新提供的技术,苹果推荐开发者使用ARC技术来管理内存;这篇笔记主要讲的是手动管理。


MRR手动管理内存也是基于引用计数的,只是需要开发者发消息给某块内存(或者说是对象)来改变这块内存的引用计数以实现内存管理(ARC技术则是编译器代替开发者完成相应的工作)。一块内存如果计数是零,也就是没有使用者,那么objective-C的运行环境会自动回收这块内存。


口诀

1、谁创建谁释放,如果你通过alloc,new或copy 来创建一个对象,那么你必须调用release或autorelease.

例如,你在一个函数中alloc生成了一个对象,且这个对象只在这个函数中被使用,那么你必须在这个函数中调用release或autorelease.如果你在一个class的某个方法alloc一个成员对象,且没有调用autorelease,那么你需要在这个类的dealloc方法中调用release;如果调用了autorelease, 那么在dealloc中什么都不需要做。


2、除了alloc,new或copy 之外的方法创建的对象都被声明了autorelease.


3、谁retain,谁release,只要你调用了retain,无论这个对象是如何生成的,你都要调用release.


1、你初始化(alloc/init)的对象,你需要释放( release)它。例如:

   NSMutableArray *array = [[NSMutableArray alloc] init];

   后,需要

   [array release];

2、你retaincopy的,你需要释放它。例如

   [array retain];

   后,需要

   [array release];

3dealloc并不将内存释放,也不会将索引计数降低,于是直接调用dealloc反而无法释放内存,在objective-c中,索引计数是起决定性作用的。


对象被创建的时候,引用计数的值为1

当引用计数为0的时候,对象将被系统统一销毁。

在一定的代码段内,对同个对象所做的copy ,alloc,retain的操作次数应当与 releaseautorelease操作的次数相等。


使用alloc创建对象,则需要使用完毕后进行释放:

string = [[NSString alloc] initWithString:@”Hello”];

[string release];


使用便利构造器创建对象,(如:NSString类的 stringWithString方法),则这个对象将被视为已经使用了autorelease则使用完毕后不需要进行释放:

 string = [NSString stringWithFormat:@”Hello”];


如果你定义了实例变量,则在你的类中实现-dealloc这个方法来释放他们。

例子:

-alloc / -release 

- (void)printHello

{      

 NSString *string;        

  string = [[NSString alloc] initWithString:@"Hello"];       

  NSLog(string);      

  // 我们使用alloc来创建了一个string 所以要release它       

 [string release];

便捷构造方法

  • (void)printHello
  • {   
  • NSString *string;   
  •  string = [NSString stringWithFormat:@"Hello"];   
  •  NSLog(string);    
  • // 我们构建这个string的时候,使用了便捷构造方法( convenience constructor )   
  •  // 所以我们认为它是 autoreleased的
  • }


   _array = [NSMutableArrayarray];

   for (NSUInteger i =0; i <100; i++) 

    {

       NSNumber *convenienceNumber = [NSNumbernumberWithInteger:i];

        [_arrayaddObject:convenienceNumber];

    }

在这个例子中,你既不需要release新对象,也不需要retain新对象

Cocoa中,当向一个集合对象中添加一个对象元素时,集合会主动持有对它的所有权。

而从集合中拿掉一个对象时,集合会主动放弃对它的所有权。


Autorelease Pool

UIKit框架已经帮你自动创建一个autorelease pool。大部分时候,你可以直接使用这个pool,不必自己创建;所以你给一个对象发送autorelease 消息,那么这个对象会加到这个UIKit自动创建的pool里。某些时候,可能需要创建一个pool:

1、没有使用UIKit框架或者其它内含autorelease pool的框架,那么要使用pool,就要自己创建。

2、如果一个循环体要创建大量的临时变量,那么创建自己的pool可以减少程序占用的内存峰值。

3、创建线程时必须创建这个线程自己的autorelease pool。

使用alloc和init消息创建pool,发送 drain消息则表示这个pool不再使用。pool的创建和drain要在同一上下文中,比如循环体内。


使用weak reference 来避免retain cycle

对一个对象发送retain消息会创建对这个对象的强引用。如果两个对象都有一个强引用指向对方,那么就形成了一个环(retain cycle)。这个环使得这两个对象都不可能被release。

弱引用指的是一种non-owning的关系,比如简单指针赋值关系。使用弱引用避免了retain cycle。但是弱引用指向的对象已经释放,那么发送消息给它会导致程序崩溃。所以,需要一点点额外的操作来使用弱引用所指的对象。


copy和retain的区别:

copy:建立一个索引计数为1的对象,然后释放旧对象

retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1

那上面是什么该死的意思呢?

copy其实是建立了一个相同的对象,而retain不是:

比如一个NSString对象,地址为0x11111,内容为@"bar".

copy到另外一个NSString之后,地址为0x2222,内容相同,新的对象retain为1,旧有对象没有变化

retain到另外一个NSString之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1

也就是说,retain是指针拷贝,copy是内容拷贝。