【问题标题】:NSAutoreleasePoolNSAutoreleasePool
【发布时间】:2011-03-29 22:22:17
【问题描述】:

我耗尽了一个自动释放池。警告*** attempt to pop an unknown autorelease pool 表示自动释放池是用不同的方法创建和排出的——这很好。

但这是否意味着这样的池没有被耗尽? 有解决办法吗?

【问题讨论】:

  • NSAutoreleasePools 不是必须在同一个范围内创建和排空吗?
  • @itaiferber 不,他们没有。如果您在带有运行循环(AppKit 或 UIKit)的应用程序中使用 ARP,那么您将在尝试挂在自动释放池上超过一个运行循环的循环时遇到问题,但自动释放池不依赖在创建它们的范围内。

标签: objective-c memory-management nsautoreleasepool


【解决方案1】:

@itaiferber 不正确,他链接到的开发博客帖子也不正确。

NSAutoreleasePools 不是在堆栈上创建的。它们像所有其他 Cocoa 对象一样在堆上分配。

我认为混乱的根源在于它在文档中说:

每个线程(包括主线程)都维护自己的 NSAutoreleasePool 对象堆栈(请参阅“线程”)。随着新池的创建,它们被添加到堆栈的顶部。当池被释放时,它们会从堆栈中移除。

文档中提到的“堆栈”不是call stack,而是stack data structure。这意味着如果你有“自动释放池1”,然后创建第二个自动释放池,然后自动释放一个对象,当第二个自动释放池耗尽时,该对象将被释放。

总而言之:只要您了解这样做对内存的影响,完全欢迎您以一种方法创建自动释放池并在另一种方法中释放它。 (这是否是糟糕的设计完全是另一个问题)

如果您最终没有清空池,它将在父自动释放池清空时为您清空

如果您释放一个不是堆栈顶部的自动释放池,这将导致堆栈上所有(未释放的)自动释放池连同它们的所有对象一起被释放。如果您在完成后忽略将释放发送到自动释放池(不推荐这样做),则它会在其嵌套的自动释放池之一被释放时被释放。

因此,如果您的自动释放池堆栈如下所示:

 _____
|  1  |  <--- most recently allocated pool
|-----|
|  2  |
|-----|
|  3  |  <--- least recently allocated pool
 -----

然后你排空池 3,池 2 和 1 也会自动排空。我猜这就是你的代码中发生的事情。您正在创建“池 1”,然后当“池 3”被排空时它会自动排空,然后您尝试自己排空池 1,但它不再有效,并且您“试图弹出一个未知数自动释放池”。

如果您尝试在 GUI 应用程序中挂起自动释放池,这个问题尤其明显。在这样的应用程序(基于 UIKit 或 AppKit)中,运行循环将在循环的每次通过时创建和销毁一个自动释放池,这意味着您在循环迭代期间创建的任何自动释放池将在下一次循环时被销毁周围。

有关这方面的更多具体信息,请参阅内存管理编程指南中的 an entire section,专门介绍自动释放池。

【讨论】:

  • 是的,我已经完整阅读了文档,但不是很清楚。从我的测试来看,自动释放池在不同范围内创建时似乎不会耗尽。我遇到了内存问题,解决方案似乎很原始:对于每种方法,在作用域的开头分配一个池并在最后将其耗尽。我试图在我的主 UIViewController 中分配一个 NSAutoreleasePool 并使用重复计时器将其耗尽,但它没有奏效。
  • @GSchv 计时器方法不起作用,因为运行循环的许多许多迭代将在创建池和下一个计时器之间传递,这意味着池将被提前销毁.您的应用似乎存在一些基本的组织缺陷。
  • 这正是我所说的。我只需要确认池只收集在同一范围内自动释放的对象。
猜你喜欢
  • 2012-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-01
  • 2011-11-09
相关资源
最近更新 更多