为啥我的自动释放对象没有被释放?

Posted

技术标签:

【中文标题】为啥我的自动释放对象没有被释放?【英文标题】:Why isn’t my autoreleased object getting released?为什么我的自动释放对象没有被释放? 【发布时间】:2011-02-25 19:58:51 【问题描述】:

我正在调试一个奇怪的内存管理错误,但我无法弄清楚。我注意到我的一些对象在内存中的停留时间比预期的要长。我检查了我所有的内存管理,最后得出了一个非常不可能的结论,即我的一些autorelease 操作不会导致release。在什么情况下可能?我创建了一个小型测试 Canary 类,它在 dealloc 中记录一条消息,并有以下测试代码:

NSLog(@"On the main thread: %i.", [NSThread isMainThread]);
[[[Canary alloc] init] autorelease];

根据代码,我们确实在主线程上,但 Canary 中的 dealloc 直到很久以后才会被调用。延迟不是确定性的,很容易花费几秒钟或更长时间。这怎么可能?应用程序在 Mac 上运行,垃圾收集已关闭(Objective-C Garbage Collection 在目标上设置为 Unsupported。)我主要习惯于 ios,是OS X 上的内存管理在某些重要方面有何不同?

【问题讨论】:

Mac OS X下的内存管理不同之处在于可以使用GC。如果您不选择 GC,那么不,没有什么不同。 【参考方案1】:

autorelease 没有按预期运行的唯一情况是当前线程上没有自动释放池。只有少数情况会发生这种情况,如果发生这种情况,您会在控制台上打印出非常响亮的日志消息。如果您没有看到该日志,则 autorelease 的行为正常。更有可能的是,您的代码中的某些内容在此 Canary 对象上调用 retain,然后从未释放它。

【讨论】:

我确定我没有保留测试对象,我实际上是在做[[[Canary alloc] init] autorelease],甚至没有使用返回值。我发现autorelease 确实会在一段时间后被调用,但延迟很大。我认为我的问题与运行循环行为有关,我将在明天添加更多信息。 autorelease 会立即被调用。零延迟。它的作用是稍后致电release。这通常发生在控制传递回运行循环时。 对不起,我没有表达清楚。我的意思是自动释放池中的release 被延迟了。【参考方案2】:

自动释放的对象在其池耗尽之前不会被释放。因此,如果您使用自动释放缓冲区循环遍历图像,则最好在每次循环时创建和排出一个池。

【讨论】:

如果你在每次循环中只创建几个对象,你不想每次都创建一个自动释放池。如果您创建 10 个或更多,那很好。此外,如果您的循环不是特别长,那么就没有真正需要自动释放池。如果您正在运行数百次重循环或数千次轻循环,那么您可能需要一个。 另外,如果您将它自动释放到应用程序的池中,它不会被释放(池不会被耗尽),直到应用程序处理一个事件。正如我们在 Growl 中发现的那样,这使得后台应用程序中的内存管理变得棘手。如果您将对象自动释放到您在main 中创建的池中,然后运行应用程序,那么该池将永远不会耗尽,因为应用程序终止将首先退出进程。 @Peter:是的,我的应用程序在后台运行,这很可能是我的问题的根源。您可以将其作为答案提交吗?我也将不胜感激。【参考方案3】:

Mike Ash 有一篇名为 More Fun With Autorelease 的博文解释了这个问题的根源。引用:

众所周知,每次去 通过事件循环,可可吹 把旧水池拿走,换一个新水池 为你,让你的所有 自动释放的对象消失了,你的 新的进入一个新的池。那 永远不会建立更多对象的方式 比在单次生产 事件循环周期。关键词是“事件循环”。在 苹果的无限智慧,那些事 不是真正的实际 NSEvents 不是 触发池。

我目前正在开发一个应用程序 在后台花费大量时间 做黑暗的,无法形容的事情 主线程上的 NSStreams。一世 遇到了一个错误,我的一个 对象可以在 处理流事件的中间, 这让它可以得到其他 之后的流媒体事件 解除分配。 (…)

明显的解决方法是简单地做 [[self retain] autorelease]之前 拨打问题电话。并修复它 做了,除了我的 dealloc 发生在我的活动中间 处理程序,它从未发生过。

直到我点击了我的应用程序的停靠图标。

至少解决方案很简单。邮政 中的 NSApplicationDefined 事件 流事件处理程序,并自动释放 对象按计划销毁。

我发誓我必须从头到尾阅读博客,这是一个很好的时间投资。

【讨论】:

是的,就是这样。我们曾经在 Growl 中做一些更骇人听闻的事情,但这就是我们现在正在做的事情,而且效果很好。

以上是关于为啥我的自动释放对象没有被释放?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 Chrome Profiler 没有为我的对象显示正确的保留路径,为啥我的对象从未被释放?

析构函数为啥能释放对象内存?

EXC_BAD_ACCESS 为啥我的对象被释放?

具有大量自动释放对象的线程如果是/否,在这种情况下是不是必须使用自动释放池,为啥?

为啥这个 ImageView 没有被释放?

为啥这段代码调用自动释放池?