高级内存管理编程指南-使用自动释放池块

使用自动释放池块

自动释放池块提供了一种机制,您可以放弃对象的所有权,但避免立即释放它(例如从方法返回对象时)。通常,您不需要创建自己的自动释放池块,但在某些情况下,您必须或者这样做是有益的。

关于 Autorelease Pool Blocks

使用标记自动释放池块@autoreleasepool,如以下示例所示:

@autoreleasepool {
    //创建自动释放对象的代码。
}

在自动释放池块的末尾,在块中接收到autorelease 消息release的对象被发送消息 - 对象release在每次在块内发送消息时接收消息autorelease

与任何其他代码块一样,自动释放池块可以嵌套:

@autoreleasepool {
    // 。。
    @autoreleasepool {
        // 。。
    }
    。。。
}

(您通常不会完全按上述方式查看代码;通常,一个源文件中的自动释放池块中的代码将调用另一个自动释放池块中包含的另一个源文件中的代码。)对于给定的autorelease消息,将release发送相应的消息在autorelease发送消息的自动释放池块的末尾。

Cocoa 总是希望代码在自动释放池块中执行,否则自动释放的对象不会被释放而应用程序会泄漏内存。(如果您autorelease在自动释放池块之外发送消息,Cocoa 会记录一个合适的错误消息。)AppKit 和 UIKit 框架处理自动释放池块中的每个事件循环迭代(例如鼠标按下事件或轻击)。因此,您通常不必自己创建自动释放池块,甚至不必查看用于创建池的代码。但是,有三种情况可能会使用您自己的自动释放池块:

  • 如果您正在编写不基于 UI 框架的程序,例如命令行工具。

  • 如果编写一个创建许多临时对象的循环。

    您可以在循环内使用自动释放池块在下一次迭代之前处理这些对象。在循环中使用自动释放池块有助于减少应用程序的最大内存占用量。

  • 如果你产生一个辅助线程。

    一旦线程开始执行,您必须创建自己的自动释放池块;否则,您的应用程序将泄漏对象。(有关详细信息,请参阅自动释放池块和线程。)

使用本地自动释放池块来减少峰值内存占用量

许多程序创建自动释放的临时对象。这些对象会添加到程序的内存占用空间,直到块结束。在许多情况下,允许临时对象累积直到当前事件循环迭代结束时不会导致过多的开销;但是,在某些情况下,您可能会创建大量临时对象,这些对象会大大增加内存占用,并且您希望更快地处置。在后面这些情况下,您可以创建自己的自动释放池块。在块结束时,临时对象被释放,这通常导致它们的释放,从而减少程序的内存占用。

以下示例显示了如何在for循环中使用本地自动释放池块。

NSArray * urls = <#一个文件URL数组#>;
for(NSURL * url in urls){
 
    @autoreleasepool {
        NSError *错误;
        NSString * fileContents = [NSString stringWithContentsOfURL:url
                                         encoding:NSUTF8StringEncoding error:&error];
        / *处理字符串,创建和自动释放更多对象。* /
    }
}

for循环一次处理一个文件。在块结束时释放在自动释放池块内fileContents发送autorelease消息的任何对象(例如)。

在自动释放池块之后,您应该将块中自动释放的任何对象视为 “已处置”。不要向该对象发送消息或将其返回给您的方法的调用者。如果必须使用自动释放池块之外的临时对象,则可以通过向retain块内的对象发送消息然后在块之后发送它autorelease来执行此操作,如以下示例所示:

- (id)findMatchingObject:(id)anObject {
 
    id匹配;
    while(match == nil){
        @autoreleasepool {
 
            / *执行创建大量临时对象的搜索。* /
            match = [self expensiveSearchForObject:anObject];
 
            if(match!= nil){
                [匹配保留]; / *保持匹配。* /
            }
        }
    }
 
    return [match autorelease]; / *让匹配去并返回它。* /
}

发送retainmatch自动释放池块并autorelease在自动释放池块之后发送到它并延长其生命周期match并允许它在循环外接收消息并返回给调用者findMatchingObject:

自动释放池块和线程

Cocoa 应用程序中的每个线程都维护自己的自动释放池块堆栈。如果您正在编写仅基于 Foundation 的程序或者分离线程,则需要创建自己的自动释放池块。

如果您的应用程序或线程长寿并且可能生成大量自动释放的对象,则应使用自动释放池块(如主线程上的 AppKit 和 UIKit); 否则,自动释放的对象会累积,并且您的内存占用会增加。如果您的分离线程没有进行 Cocoa 调用,则不需要使用自动释放池块。

注意:  如果使用 POSIX 线程 API 而不是创建辅助线程NSThread,除非 Cocoa 处于多线程模式,否则不能使用 Cocoa。Cocoa 仅在分离其第一个NSThread对象后才进入多线程模式。要在辅助 POSIX 线程上使用 Cocoa,您的应用程序必须首先分离至少一个NSThread可以立即退出的对象。您可以使用NSThread类方法测试 Cocoa 是否处于多线程模式isMultiThreaded

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值