从 C++ 到 Objective-C(14):内存管理(续).doc_第1页
从 C++ 到 Objective-C(14):内存管理(续).doc_第2页
从 C++ 到 Objective-C(14):内存管理(续).doc_第3页
从 C++ 到 Objective-C(14):内存管理(续).doc_第4页
全文预览已结束

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

从 C+ 到 Objective-C(14):内存管理(续)作者:DevBean日期: 2011 年 03 月 30 日发表评论(5)查看评论autorelease 池上一节中我们了解到 autorelease 的种种神奇之处:它能够在合适的时候自动释放分配的内存。但是如何才能让便以其之道什么时候合适呢?这种情况下,垃圾收集器是最好的选择。下面我们将着重讲解垃圾收集器的工作原理。不过,为了了解垃圾收集器,就不得不深入了解 autorelease 的机制。所以我们要从这里开始。当对象收到 autorelease 消息的时候,它会被注册到一个“autorelease 池”。当这个池被销毁时,其中的对象也就被实际的销毁。所以,现在的问题是,这个池如何管理?答案是丰富多彩的:如果你使用 Cocoa 开发 GUI 界面,基本不需要做什么事情;否则的话,你应该自己创建和销毁这个池。拥有图形界面的应用程序都有一个事件循环。这个循环将等待用户动作,使应用程序响应动作,然后继续等待下一个动作。当你使用 Cocoa 创建 GUI 程序时,这个 autorelease 池在事件循环的一次循环开始时被自动创建,然后在循环结束时自动销毁。这是合乎逻辑的:一般的,一个用户动作都会触发一系列任务,临时变量的创建和销毁一般不会影响到下一个事件。如果必须要有可持久化的数据,那么你就要手动地使用 retain 消息。另一方面,如果没有 GUI,你必须自己建立 autorelease 池。当对象收到 autorelease 消息时,它能够找到最近的 autorelease 池。当池可以被清空时,你可以对这个池使用 release 消息。一般的,命令行界面的 Cocoa 程序都会有如下的代码:int main(int argc, char* argv) NSAutoreleasePool* pool = NSAutoreleasePool alloc init; /. pool release; return 0;注意在 Mac OS X 10.5 的 NSAutoreleasePool 类新增加了一个 drain 方法。这个方法等价于:当垃圾收集器可用时做 release 操作;否则则触发运行垃圾收集。这对编写在两种情况下都适用的代码时是很有用的。注意,这里实际上是说,现在有两种环境:引用计数和垃圾回收。Mac OS 的新版本都会支持垃圾收集器,但是 iOS 却不支持。在引用计数环境下,NSAutoreleasePool 的 release 方法会给池中的所有对象发送 release 消息,如果对象注册了多次,就会多次给它发 release。drain 和 release 在应用计数环境下是等价的。在垃圾收集的环境下,release 不做任何事情,drain 则会触发垃圾收集。使用多个 autorelease 池在一个程序中使用多个 autorelease 池也是可以的。对象收到 autorelease 消息时会注册到最近的池。因此,如果一个函数需要创建并使用很大数量临时对象,为了提高性能,可以创建一个局部的 autorelease 池。这种情况下,这些临时变量就可以及时的被销毁,从而在函数返回时就将内存释放出来。autorelease 的注意点使用 autorelease 可能会有一些误用情况,需要我们特别注意。 首先,非必要地发送多个 autorelease 类似发送多个 release 消息,在内存池清空时会引起内存错误; 其次,即使 release 可以由 autorelease 替代,也不能滥用 autorelease。因为 autorelease 要比正常的 release 消耗资源更多。另外,不必要的推迟 release 操作无疑会导致占用大量内存,容易引起内存泄露。autorelease 和 retain多亏了 autorelease,方法才能够创建能够自动释放的对象。但是,长时间持有对象是一种很常见的需求。在这种情形下,我们可以向对象发送 retain 消息,然后在后面手动的 release。这样,这个对象实际上可以从两个角度去看待: 从函数开发者的角度,对象的创建和释放都是有计划的; 从函数调用者的角度,使用了 retain 之后,对象的生命期变长了(使用 retain 将使其引用计数器加 1),为了让对象能够正确地被释放,调用者必须负责将计数器再减 1。我们来理解一下这句话。对于一个函数的开发者,如果他不使用 autorelease,那么,他使用 alloc 创建了一个对象并返回出去,那么,他需要负责在合适的时候对这个对象做 release 操作。也就是说,从函数开发者的角度,这个对象的计数器始终是 1,一次 release 是能够被正常释放的。此时,函数调用者却使用 retain 将计数器加 1,但是开发者不知道对象的计数器已经变成 2 了,一次 release 不能释放对象。所以,调用者必须注意维护计数器,要调用一次 release 将其恢复至 1。Convenience constructor, virtual constructor将构造对象的过程分成 alloc 和 init 两个阶段,有时候显得很罗嗦。好在我们有一个 convenience constructor 的概念。这种构造函数应该使用类名做前缀,其行为类似 init,同时要实现 alloc。但是,它的返回对象需要注册到一个内部的 autorelease 池,如果没有给它发送 retain 消息时,这个对象始终是一个临时对象。例如:/ 啰嗦的写法NSNumber* zero_a = NSNumber alloc initWithFloat:0.0f;.zero_a release;./ 简洁一些的NSNumber* zero_b = NSNumber numberWithFloat:0.0f;./ 不需要 release根据我们前面对内存管理的介绍,这种构造函数的实现是基于 autorelease 的。但是其底层代码并不那么简单,因为这涉及到对 self 的正确使用。事实上,这种构造函数都是类方法,所以 self 指向的是 Class 类型的对象,就是元类类型的。在初始化方法,也就是一个实例方法中,self 指向的是这个类的对象的实例,也就是一个“普通的”对象。编写错误的这种构造函数是很容易的。例如,我们要创建一个 Vehicle 类,包含一个 color 数据,编写如下的代码:/ The Vehicle classinterface Vehicle : NSObject NSColor* color;-(void) setColor:(NSColor*)color;/ 简洁构造函数+(id) vehicleWithColor:(NSColor*)color;end其对应的实现是:/ 错误的实现+(Vehicle*) vehicleWithColor:(NSColor*)color / self 不能改变 self = self alloc init; / 错误! self setColor:color; return self autorelease;记住我们前面所说的,这里的 self 指向的是 Class 类型的对象。/ 比较正确的实现+(id) vehicleWithColor:(NSColor*)color id newInstance = Vehicle alloc init; / 正确,但是忽略了有子类的情况 newInstance setColor:color; return newInstance autorelease;我们来改进一下。Objective-C 中,我们可以实现 virtual constructor。这种构造函数通过内省的机制来了解到自己究竟应该创建哪种类的对象,是这个类本身的还是其子类的。然后它直接创建正确的类的实例。我们可以使用一个 class 方法(注意,class 在 Objective-C 中不是关键字);这是 NSObject 的一个方法,返回当前对象的类对象(也就是 meta-class 对象)。implementation Vehicle+(id) vehicleWithColor:(NSColor*)color id newInstance = self clas

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论