【问题标题】:How does the NSAutoreleasePool autorelease pool work?NSAutoreleasePool 自动释放池是如何工作的?
【发布时间】:2010-09-09 02:08:06
【问题描述】:

据我了解,使用 allocnewcopy 创建的任何内容都需要手动释放。例如:

int main(void) {
    NSString *string;
    string = [[NSString alloc] init];
    /* use the string */
    [string release];
}

不过,我的问题是,这不是同样有效吗?:

int main(void) {
    NSAutoreleasePool *pool;
    pool = [[NSAutoreleasePool alloc] init];
    NSString *string;
    string = [[[NSString alloc] init] autorelease];
    /* use the string */
    [pool drain];
}

【问题讨论】:

    标签: objective-c memory-management nsautoreleasepool foundationkit


    【解决方案1】:

    是的,您的第二个代码片段完全有效。

    每次-autorelease 被发送到一个对象,它被添加到最里面的自动释放池。当池耗尽时,它只是向池中的所有对象发送-release。

    自动释放池只是一种方便,它允许您将发送 -release 推迟到“稍后”。 “稍后”可能发生在多个地方,但在 Cocoa GUI 应用程序中最常见的是在当前运行循环周期结束时。

    【讨论】:

    • 如果我没有循环,当前运行循环循环的终点在哪里?
    • “最外层”不应该是“最里面”吗?
    • an object 应该是 an object that is a subclass of NSObject or NSProxy and doesn't override -autorelease
    • 编辑:将最外层更改为最内层。
    • 重要:如果您使用自动引用计数 (ARC),则不能直接使用自动释放池。相反,您使用 @autoreleasepool 块。来自developer.apple.com/library/mac/#documentation/Cocoa/Reference/…
    【解决方案2】:

    NSAutoreleasePool:流失与释放

    由于drainrelease 的功能似乎会引起混淆,因此在这里可能需要澄清一下(尽管the documentation...对此进行了说明)。

    严格来说,从大局来看drain等同于release

    在引用计数环境中,drain 确实执行与release 相同的操作,因此两者在这个意义上是等效的。需要强调的是,这意味着如果您使用drain 而不是release,您确实不会泄漏池。

    在垃圾收集环境中,release 是无操作的。因此它没有效果。另一方面,drain 包含对收集器的提示,即它应该“在需要时收集”。因此在垃圾收集环境中,使用drain 有助于系统平衡收集扫描。

    【讨论】:

    • 基本上不可能“泄露”NSAutoreleasePool。这是因为池像堆栈一样运行。实例化一个池将该池推到该线程自动释放池堆栈的顶部。 -release 导致该池从堆栈中弹出并且任何被推到它上面的池,但无论出于何种原因都没有弹出。
    • 这和我写的有什么关系?
    • 我喜欢他花时间加粗和的方式。 捕捉!
    【解决方案3】:

    正如已经指出的,您的第二个代码 sn-p 是正确的。

    我想建议一种更简洁的方式来使用适用于所有环境(引用计数、GC、ARC)的自动释放池,并且还可以避免耗尽/释放混淆:

    int main(void) {
      @autoreleasepool {
        NSString *string;
        string = [[[NSString alloc] init] autorelease];
        /* use the string */
      }
    }
    

    在上面的示例中,请注意 @autoreleasepool 块。这记录在here

    【讨论】:

    • 请注意,ARC 不允许自动释放。
    • 为了澄清,必须将@autoreleasepool 块与ARC一起使用。
    【解决方案4】:

    不,你错了。文档明确指出,在非 GC 下,-drain 等价于 -release,这意味着 NSAutoreleasePool 将不会被泄露。

    【讨论】:

    【解决方案5】:

    我从 Apple 那里读到的内容: “在自动释放池块结束时,在块内收到自动释放消息的对象会收到释放消息——对象每次在块内收到自动释放消息时都会收到释放消息。”

    https://developer.apple.com/library/mac/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html

    【讨论】:

      【解决方案6】:

      向一个对象发送自动释放而不是释放可以延长该对象的生命周期,至少直到池本身被耗尽(如果该对象随后被保留,则可能会更长)。一个对象可以多次放入同一个池中,在这种情况下,每次放入池中都会收到一条释放消息。

      【讨论】:

        【解决方案7】:

        是和不是。如果您在垃圾收集(不是内存管理)环境下运行它,您最终会释放字符串内存,但通过使用排水而不是释放将 NSAutoreleasePool 对象“泄漏”到内存中。这个“泄漏”只是让 NSAutoreleasePool 的实例“无法访问”,就像在 GC 下没有强指针的任何其他对象一样,并且该对象将在下次 GC 运行时被清理,这很可能是在调用 -drain 之后直接进行的:

        排水

        在垃圾回收环境中,如果自上次回收后分配的内存大于当前阈值,则触发垃圾回收;否则表现为释放。 ... 在垃圾回收的环境下,这个方法最终调用objc_collect_if_needed

        否则,它类似于-release 在非 GC 下的行为,是的。正如其他人所说,-release 在 GC 下是无操作的,因此确保池在 GC 下正常运行的唯一方法是通过-drain,而非 GC 下的-drain-release 在非 GC 下的工作方式完全相同非 GC,并且可以说也更清楚地传达了它的功能。

        我应该指出,您的声明“使用 new、alloc 或 init 调用的任何内容”不应包含“init”(但应包含“copy”),因为“init”不分配内存,它只设置对象(构造函数)。如果你收到一个分配的对象,而你的函数只调用了 init,你就不会释放它:

        - (void)func:(NSObject*)allocd_but_not_init
        {
            [allocd_but_not_init init];
        }
        

        这不会比您已经开始使用的内存消耗更多的内存(假设 init 不会实例化对象,但无论如何您都不应对这些负责)。

        【讨论】:

        • 当您关于排水的信息不完全正确时,我不愿意将此答案视为已接受。请参阅developer.apple.com/documentation/Cocoa/Reference/Foundation/… 更新,我会重新接受。
        • 回复有什么不准确的地方?在垃圾收集环境中(如前所述),drain 不会删除 AutoReleasePool,因此您泄漏内存,除非您使用 release。我列出的报价直接来自马的嘴,正在流失的文档。
        • Loren:在GC下,-[NSAutoreleasePool drain]会触发一个collection。 -retain、-release 和 -autorelease 都被收集器忽略;这就是为什么 -drain 用于 GC 下的自动释放池。
        • 在 'drain' 的文档中:在托管内存环境中,这与调用 release 的行为相同。因此,如果您使用 'drain' 而不是释放,您将不会泄漏内存。
        • -[NSAutoreleasePool release] 在垃圾收集环境中是无操作的。 -[NSAutoreleasePool drain] 适用于引用计数和垃圾收集环境。
        猜你喜欢
        • 2011-07-09
        • 1970-01-01
        • 2013-04-16
        • 1970-01-01
        • 2013-01-18
        • 2012-02-06
        • 2013-04-18
        • 2014-09-02
        • 2011-08-04
        相关资源
        最近更新 更多