OC 内存管理

本章介绍如何使用OC和Cocoa进行内存管理。

 

OC2有垃圾回收机制。

 

1、对象生命周期

1.1、引用计数

Cocoa采用一种称为引用计数(reference counting)的技术,有时也叫做保留计数

每个对象有一个与之相关的整数,称作它的引用计数器或保留计数器。当某段代码需要访问一个对象时,该代码将该对象的保留计数器值加1,表示“我要访问该对象”。当这段代码结束对象访问时,将对象的保留计数器值减1,表示它不再访问该对象。当保留计数器值为0时,表示不再有代码访问该对象了,因此该对象将被销毁,其占用的内存被系统回收以便重用。

当使用alloc、new方法或者通过copy消息(生成接收对象的一个副本)创建一个对象时,对象的保留计数器值被设置为1.要增加对象的保留计数器值,可以给对象发送一条retain消息。要减少对象的保留计数器值,可以给对象发送一条release消息。

当一个对象因其保留计数器值归0而被销毁时,OC自动向对象发送一条dealloc消息。可以在自己的对象中重写dealloc方法。一定不要直接调用dealloc方法。可以利用OC在需要销毁对象时调用dealloc方法。要获得保留计数器的当前值,可以发送retainCount消息。

- (id) retain;

- (void) release;

- (unsigned) retainCount;

retain方法返回一个id类型的值。通过这种方式,可以嵌套执行带有其它消息发送参数的保留调用,增加对象的保留计数器值并要求对象完成某种操作。如,[[car retain] setTire: tire atIndex: 2];

 

1.2、对象所有权

object ownership,当某个实体“拥有一个对象”时,就意味着该实体要负责确保对其拥有的对象进行清理。

如果一个对象具有指向其它对象的实例变量,则称该对象拥有这些对象。如果一个函数创建了一个对象,则称该函数拥有它创建的这个对象。

当多个实体拥有某个特定对象时,对象的所有权关系更复杂了。

 

1.3、访问方法中的保留和释放

 

 

2、自动释放

2.1、所有对象全部入池

Cocoa中有一个自动释放池(autorelease pool)的概念。NSAutoreleasePool

它是一个存放实体的池(集合),这些实体可能是对象,能够被自动释放

NSObject类提供了一个autorelease方法

- (id) autorelease;

该方法预先设定了一条在将来某个时间发送的release消息,其返回值是接收消息的对象。retain消息采用了相同的技术,使嵌套调用更加容易。当给一个对象发送autorelease消息时,实际上是将该对象添加到NSAutoreleasePool中。当自动释放池被销毁时,会向该池中的所有对象发送release消息。

 

可以很好地管理内存的description方法:

- (NSString *) description

{

  NSString *description;

  description=[[NSString alloc] initWithFormat: @"i am %d years old",4];

  return ([description autorelease]);

}

NSLog(@"%@",[someObject description]);

 

2.2、自动释放池的销毁时间

自动释放池什么时候被销毁,以便可以向其包含的所有对象发送release消息?什么时候创建自动释放池呢?

在我们一直使用的Foundation库工具中,创建和销毁自动释放池的方法非常明确:

NSAutoreleasePool *pool;

pool=[[NSAutoreleasePool alloc] init];

...

[pool release];

创建一个自动释放池时,该池自动成为活动的池。释放该池时,其保留计数值归0,然后该池被销毁。销毁过程中,该池释放所包含的所有对象。

 

当使用AppKit时,Cocoa定期自动为你创建和销毁自动释放池。通常是在程序处理完当前事件(如鼠标单击或按键)以后执行这些操作。可以使用任意多的自动释放对象,当不再使用它们时,自动释放池将自动为你清理这些对象。

 

2.3、自动释放池的工作过程

首先创建一个自动释放池:

NSAutoreleasePool *pool;

pool=[[NSAutoreleasePool alloc] init];

现在任何时候向一个对象发送autorelease消息,该对象都会被添加到这个自动释放池中:

 

最后销毁自动释放池,NSAutoreleasePool当作一个普通对象release:

[pool release];

 

 

3、Cocoa内存管理机制

现在已经学习了一些内存管理方法:retain、release、autorelease。

Cocoa有许多内存管理约定,它们都是一些很简单的规则,可一致地应用于整个工具包。

这些规则如下:

1)当你使用new、alloc或copy方法创建一个对象时,该对象的保留计数器值为1。当不再使用该对象时,你要负责向该对象发送一条release或autorelease消息。这样,该对象将在其使用寿命结束时被销毁。

2)当你通过任何其它方法获得一个对象时,则假设该对象的保留计数器值为1,而且已经被设置为自动释放,你不需要执行任何操作来确保该对象被清理。如果你打算在一段时间内拥有该对象,则需要保留它并确保在操作完成时释放它。

3)如果你保留了某个对象,你需要(最终)释放或自动释放该对象,必须保持retain方法和release方法的使用次数相等。

 

3.1、临时对象

如果使用new、alloc或copy方法获得一个对象,则需要安排该对象的死亡。

 

如果使用任何其它方法获得一个对象,例如arrayWithCapacity:方法,则不需要关心如何销毁该对象。

arrayWithCapacity: 方法不属于alloc、new、copy这三个方法中的一个,因此可以假设该对象被返回时保留计数器值为1且已经被设置为自动释放1.

 

3.2、拥有对象

通常,你可能希望在多个代码行中一直拥有某个对象。常见的方法是:在其他对象的实例变量中使用这些对象,将他们加入到诸如NSArray或NSDictionary等集合中,或者将其作为全局变量使用。

如果你使用除alloc、new或copy以外的方法获得一个对象,你需要保留该对象。考虑编写GUI应用程序时事件循环的情况。你希望保留自动释放的对象,使这些对象在当前的事件循环结束以后仍能继续存在。

 

3.3、垃圾回收

OC2.0引入了自动内存管理机制,也称垃圾回收。

对于已经创建和使用的对象,当你忘记清理它们时,系统会自动识别哪些对象仍在使用,哪些对象可以回收。启用垃圾回收非常简单,只不过这是一种可选择启用的功能。

启用垃圾回收以后,通常的内存管理命令全部都变成了空操作指令,不执行任何操作。

OC的垃圾回收器是一种继承性的垃圾回收器。与那些已经存在了一段时间的对象相比,新创建的对象更可能被当成垃圾。垃圾回收器定期检查变量和对象以及它们之间的指针,当发现没有任何变量指向某个对象时,就将该对象视为应该被丢弃的垃圾

如果在一个实例变量中指向某个对象,一定要在某个时候使将该实例变量赋值为nil,已取消对该对象的引用并使垃圾回收器知道该对象可以被清理了。

 

与自动释放池一样,垃圾回收器也是在事件循环结束时触发的。当然,如果不是编写GUI程序,也可以自己触发垃圾回收器。

如果开发iPhone软件,则不能使用垃圾回收。实际上,在编写iPhone程序时,苹果公司建议不在自己的代码中使用autorelease方法,同时还要避免使用创建自动释放对象的便利函数。

 

posted @ 2020-06-03 20:31  吉吉boy  阅读(306)  评论(0编辑  收藏  举报