【问题标题】:NSAutoreleasePool carrying across methods?NSAutoreleasePool 跨方法携带?
【发布时间】:2009-06-18 03:23:14
【问题描述】:

我正在构建一个 iPhone 应用程序,我在其中分离一些线程以在后台执行长时间运行的工作,以免挂起 UI。我知道线程需要 NSAutoreleasePool 实例来进行内存管理。我不确定线程​​方法是否调用另一个方法 - 该方法是否还需要 NSAutoreleasePool?

示例代码:

- (void)primaryMethod {
    [self performSelectorInBackground:@selector(threadedMethod) withObject:nil];
}

- (void)threadedMethod {
    NSAutoreleasePool *aPool = [[NSAutoreleasePool alloc] init];

    // Some code here

    [self anotherMethod];

    // Maybe more code here

    [aPool drain];
}

- (void)anotherMethod {
    // More code here
}

我问的原因是我收到的错误是对象正在自动释放而没有适当的池,并且“只是泄漏”。

我还看到人们根本没有设置自动释放池的其他问题,我理解为什么需要自动释放池。我特别想知道(在此示例中)threadedMethod 中创建的自动释放池是否适用于anotherMethod 中创建的对象。

【问题讨论】:

  • 简短的回答是肯定的。查看我的回复。

标签: iphone objective-c cocoa memory-management autorelease


【解决方案1】:

回答你的问题,是的,anotherMethod 正在使用你在 threadedMethod 中创建的 NSAutoreleasePool,当 aPool 被释放/耗尽时,你在那里自动释放的任何东西都会被释放。

因此,您的错误不太可能直接源于此代码(除非还有更多情况发生)。

在 _NSAutoreleaseNoPool 上放置一个断点(在 Breakpoints 窗口中按名称添加它)并在调试器中运行您的代码,它会在没有池的情况下调用 autorelease 时停止,这应该可以解决您的问题。

【讨论】:

  • +1 用于 _NSAutoreleaseNoPool 建议的断点。这有助于消除错误消息。
  • 他们呢?从 threadedMethod 中调用的任何方法、类或其他方法都将使用在 threadedMethod 中创建的 NSAutoreleasePool(或在其中创建更深嵌套的其他一些 NSAutoreleasePool。
【解决方案2】:

在您的示例中,是的,由于 [self anotherMethod] 的调用嵌套在 -(void)threadedMethod 内,因此 NSAutoreleasePool 正在执行跨方法。

  • 问:NSAutoreleasePool 跨方法携带?
  • 答:这取决于:
    1. 跨嵌套调用,是的。
    2. 跨兄弟调用,没有。

不管怎样,当父作用域消失时,NSAutoreleasePool 实例本身就会超出作用域。 -在你的例子中,在-(void)threadedMethod { }的最后

前面提到的文章 (http://thegothicparty.com/dev/macos/nsautoreleasepool/) 说得很清楚。

【讨论】:

    【解决方案3】:

    自动释放池确实会传递给另一个方法。但是,当您的线程函数结束时,您应该调用 [aPool release] 而不是 [aPool drain]。它们大致相同,但 aPool 释放会导致 NSAutoreleasePool 释放自身以及池中的所有其他对象。当您的线程函数在调用 drain 后结束时,自动释放池的保留计数仍然为 +1!奇怪的是,“刚刚泄漏”的对象是 aPool!

    编辑:

    Jim Puls 说得对,释放和消耗是等价的。 Apple 文档明确表示它们在非垃圾收集环境中是相同的,并且在垃圾收集的情况下排水效果更好。不阅读文档是我的错!

    这是一篇介绍 NSAutoreleasePools 的一般概述的文章 - 它应该有助于为您指明正确的方向。由于有一个自动释放池的虚拟堆栈,因此最上面的一个将在您的应用程序中的任何地方使用 - 无论对象在哪里被自动释放。

    http://thegothicparty.com/dev/macos/nsautoreleasepool/

    【讨论】:

    • 详细说明,自动释放池本身不被引用计数;它们形成一个堆栈,其中自动释放的对象进入最顶层的池。 -drain、-release 和每次运行循环迭代的结束只是弹出自动释放池的堆栈。
    • Ben:这在类方法中也适用吗?比如说,如果 anotherClass 中存在 anotherMethod,并且我在 threadedMethod 中实例化了 anotherClass - 在 [anotherClass anotherMethod] 中运行的代码是否仍会适当地自动释放?
    • 是的,它们将被正确释放。您可以将自动释放池视为调用堆栈中某个位置的假想屏障。在最新的屏障(自动释放池)建立后自动释放的所有内容都将在该屏障被拆除时释放。您可以按照执行流程查看它是如何工作的。请注意,如果 -anotherMethod 创建自己的自动释放池并在退出之前将其排空,则在该方法中创建的任何自动释放对象都将属于最内层的池,而不是 -threadedMethod 中的那个。
    • 感谢 Ben 和 Quinn 的回答!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-14
    • 2014-08-10
    • 2022-01-06
    • 2012-05-11
    • 1970-01-01
    • 1970-01-01
    • 2011-03-29
    相关资源
    最近更新 更多