19

我读到这个:

如果您曾经在应用程序中创建辅助线程,则需要为其提供自己的自动释放池。自动释放池及其包含的对象在中进一步讨论

在 iOS 5 开发者手册中。

我正在使用 ARC 进行编译。我一直在创建许多后台线程,看来我做得很好。我的后台线程都不是长时间运行的。所有这些对象都会被主线程的自动释放池释放吗?要不然是啥?

这就是我所说的后台线程:

+(void)doBackground:(void (^)())block
{
    //DISPATCH_QUEUE_PRIORITY_HIGH
    //dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0), ^{
    dispatch_async(dispatch_get_global_queue(-2,0), ^{
        block();
    });
}

我应该把它改成

+(void)doBackground:(void (^)())block
{
    //DISPATCH_QUEUE_PRIORITY_HIGH
    //dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0), ^{
    dispatch_async(dispatch_get_global_queue(-2,0), ^{
        @autoreleasepool{
        block();
        }
    });
}
4

2 回答 2

35

如果您不为新线程创建自动释放池,则至少将其视为程序员错误。这对您的程序是否致命是由您的程序实现定义的。经典问题是对象泄漏,因此对象dealloc永远不会被执行(可能是致命的)。

在 ARC 下创建自动释放池的现代方法是:

void MONThreadsEntry() { // << entry is e.g. a function or method
  @autoreleasepool {
    ...do your work here...
  }
}

更详细地说,自动释放池表现为线程本地堆栈——您可以推送和弹出,但在该线程上的任何内容被自动释放之前,总是应该有一个。自动释放消息不会从一个线程转移到另一个线程。

如果您“创建线程”的想法是使用更高级别的异步机制(例如使用 NSOperationQueue),或者如果底层实现创建辅助线程及其自己的自动释放池,您可能看不到问题(例如在控制台中或泄漏) .

无论如何,与其猜测何时创建自动释放池,只需了解您需要在哪里创建它们以及何时应该创建它们。这一切都是明确的——不需要猜测,也不需要害怕创造它们。

同样,如果您使用较低级别的抽象,则永远不需要为线程创建自动释放池,并且永远不会在该线程上自动释放对象。例如,pthreads 和纯 C 实现不需要担心自动释放池(除非您使用的某些 API 假设它们已经到位)。

甚至 Cocoa 应用程序中的主线程也需要一个自动释放池——它通常不是您编写的东西,因为它存在于项目模板中。

更新——调度队列

针对更新的问题:是的,您仍然应该为在调度队列下运行的程序创建自动释放池——请注意,使用调度队列,您不会创建线程,因此这与原始问题完全不同。原因:虽然调度队列确实管理自动释放池,但不能保证它们被清空的时间/点。也就是说,你的对象会被释放(在某个时候),但你应该还在这种情况下创建自动释放池,因为该实现可能(理论上)每运行 10,000 个块或大约每天都会耗尽池。因此,在这种情况下,它实际上只在某些情况下是致命的,例如当您最终消耗过多内存时,或者当您的程序期望其对象将以某种确定的方式被销毁时 - 例如,您可能正在加载或处理图像如果由于自动释放池而意外延长了这些图像的寿命,则后台和最终会消耗大量内存。另一个示例是共享资源或全局对象,您可以在其中响应通知或引入竞争条件,因为您的“阻塞本地”对象的寿命可能比您预期的要长得多。

于 2012-09-25T04:17:26.253 回答
4

现在似乎自动为新线程创建了自动释放池。不知道这种情况何时发生变化以及为什么文档状态相反,仅此而已。

于 2012-09-25T01:44:46.033 回答