从 c++ 到 objective-c(14):内存管理(续)

上传人:wm****3 文档编号:42462308 上传时间:2018-06-02 格式:DOC 页数:4 大小:47KB
返回 下载 相关 举报
从 c++ 到 objective-c(14):内存管理(续)_第1页
第1页 / 共4页
从 c++ 到 objective-c(14):内存管理(续)_第2页
第2页 / 共4页
从 c++ 到 objective-c(14):内存管理(续)_第3页
第3页 / 共4页
从 c++ 到 objective-c(14):内存管理(续)_第4页
第4页 / 共4页
亲,该文档总共4页,全部预览完了,如果喜欢就下载吧!
资源描述

《从 c++ 到 objective-c(14):内存管理(续)》由会员分享,可在线阅读,更多相关《从 c++ 到 objective-c(14):内存管理(续)(4页珍藏版)》请在金锄头文库上搜索。

1、从从 C+ 到到 Objective-C(14):内存管理(续):内存管理(续)作者: DevBean 日期: 2011 年 03 月 30 日发表评论 (5)查看评论autorelease 池池上一节中我们了解到 autorelease 的种种神奇之处:它能够在合适的时候自动释放分配的内存。但是如何才能让便以其之道什么时候合适呢?这种情况下,垃圾收集器是最好的选择。下面我们将着重讲解垃圾收集器的工作原理。不过,为了了解垃圾收集器,就不得不深入了解 autorelease 的机制。所以我们要从这里开始。当对象收到 autorelease 消息的时候,它会被注册到一个“autorelease 池

2、”。当这个池被销毁时,其中的对象也就被实际的销毁。所以,现在的问题是,这个池如何管理?答案是丰富多彩的:如果你使用 Cocoa 开发 GUI 界面,基本不需要做什么事情;否则的话,你应该自己创建和销毁这个池。拥有图形界面的应用程序都有一个事件循环。这个循环将等待用户动作,使应用程序响应动作,然后继续等待下一个动作。当你使用 Cocoa 创建 GUI 程序时,这个 autorelease 池在事件循环的一次循环开始时被自动创建,然后在循环结束时自动销毁。这是合乎逻辑的:一般的,一个用户动作都会触发一系列任务,临时变量的创建和销毁一般不会影响到下一个事件。如果必须要有可持久化的数据,那么你就要手动

3、地使用 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

4、类新增加了一个 drain 方法。这个方法等价于:当垃圾收集器可用时做 release 操作;否则则触发运行垃圾收集。这对编写在两种情况下都适用的代码时是很有用的。注意,这里实际上是说,现在有两种环境:引用计数和垃圾回收。Mac OS 的新版本都会支持垃圾收集器,但是 iOS 却不支持。在引用计数环境下,NSAutoreleasePool 的 release 方法会给池中的所有对象发送 release 消息,如果对象注册了多次,就会多次给它发 release。drain 和 release 在应用计数环境下是等价的。在垃圾收集的环境下,release 不做任何事情,drain 则会触发垃圾收集

5、。使用多个使用多个 autorelease 池池在一个程序中使用多个 autorelease 池也是可以的。对象收到 autorelease 消息时会注册到最近的池。因此,如果一个函数需要创建并使用很大数量临时对象,为了提高性能,可以创建一个局部的 autorelease 池。这种情况下,这些临时变量就可以及时的被销毁,从而在函数返回时就将内存释放出来。autorelease 的注意点的注意点使用 autorelease 可能会有一些误用情况,需要我们特别注意。首先,非必要地发送多个 autorelease 类似发送多个 release 消息,在内存池清空时会引起内存错误;其次,即使 rele

6、ase 可以由 autorelease 替代,也不能滥用 autorelease。因为 autorelease 要比正常的 release 消耗资源更多。另外,不必要的推迟 release 操作无疑会导致占用大量内存,容易引起内存泄露。autorelease 和和 retain多亏了 autorelease,方法才能够创建能够自动释放的对象。但是,长时间持有对象是一种很常见的需求。在这种情形下,我们可以向对象发送 retain 消息,然后在后面手动的 release。这样,这个对象实际上可以从两个角度去看待:从函数开发者的角度,对象的创建和释放都是有计划的;从函数调用者的角度,使用了 reta

7、in 之后,对象的生命期变长了(使用 retain 将使其引用计数器加 1) ,为了让对象能够正确地被释放,调用者必须负责将计数器再减 1。我们来理解一下这句话。对于一个函数的开发者,如果他不使用 autorelease,那么,他使用 alloc 创建了一个对象并返回出去,那么,他需要负责在合适的时候对这个对象做 release 操作。也就是说,从函数开发者的角度,这个对象的计数器始终是 1,一次 release 是能够被正常释放的。此时,函数调用者却使用 retain 将计数器加 1,但是开发者不知道对象的计数器已经变成 2 了,一次 release 不能释放对象。所以,调用者必须注意维护计

8、数器,要调用一次 release 将其恢复至 1。Convenience constructor, virtual constructor将构造对象的过程分成 alloc 和 init 两个阶段,有时候显得很罗嗦。好在我们有一个 convenience constructor 的概念。这种构造函数应该使用类名做前缀,其行为类似 init,同时要实现 alloc。但是,它的返回对象需要注册到一个内部的 autorelease 池,如果没有给它发送 retain 消息时,这个对象始终是一个临时对象。例如:/ 啰嗦的写法NSNumber* zero_a = NSNumber alloc initWi

9、thFloat:0.0f;.zero_a release;./ 简洁一些的NSNumber* zero_b = NSNumber numberWithFloat:0.0f;./ 不需要 release根据我们前面对内存管理的介绍,这种构造函数的实现是基于 autorelease 的。但是其底层代码并不那么简单,因为这涉及到对 self 的正确使用。事实上,这种构造函数都是类方法,所以 self 指向的是 Class 类型的对象,就是元类类型的。在初始化方法,也就是一个实例方法中,self 指向的是这个类的对象的实例,也就是一个“普通的”对象。编写错误的这种构造函数是很容易的。例如,我们要创建一

10、个 Vehicle 类,包含一个 color 数据,编写如下的代码:/ The Vehicle classinterface Vehicle : NSObjectNSColor* color;-(void) setColor:(NSColor*)color;/ 简洁构造函数+(id) vehicleWithColor:(NSColor*)color;end其对应的实现是:/ 错误的实现+(Vehicle*) vehicleWithColor:(NSColor*)color/ self 不能改变self = self alloc init; / 错误!self setColor:color;re

11、turn self autorelease;记住我们前面所说的,这里的 self 指向的是 Class 类型的对象。/ 比较正确的实现+(id) vehicleWithColor:(NSColor*)colorid newInstance = Vehicle alloc init; / 正确,但是忽略了有子类的情况newInstance setColor:color;return newInstance autorelease;我们来改进一下。Objective-C 中,我们可以实现 virtual constructor。这种构造函数通过内省的机制来了解到自己究竟应该创建哪种类的对象,是这个

12、类本身的还是其子类的。然后它直接创建正确的类的实例。我们可以使用一个 class 方法(注意,class 在 Objective-C 中不是关键字);这是 NSObject 的一个方法,返回当前对象的类对象(也就是 meta-class 对象)。implementation Vehicle+(id) vehicleWithColor:(NSColor*)colorid newInstance = self class alloc init; / 完美!我们可以在运行时识别出类newInstance setColor:color;return newInstance autorelease;endinterface Car : Vehicle .end./ 创建一个 red Carid car = Car vehicleWithColor:NSColor redColor;

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 生活休闲 > 社会民生

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号