使用ARC,每个线程都没有自动释放池是致命的吗?

use*_*951 18 multithreading cocoa-touch nsautoreleasepool ios

我看了这个:

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

在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();
    });
}
Run Code Online (Sandbox Code Playgroud)

我应该改变吗?

+(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();
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

jus*_*tin 34

如果您没有为新线程创建自动释放池,请至少考虑它是程序员错误.这对你的程序是否致命是由程序的实现来定义的.经典问题是泄漏的对象,因此dealloc从未执行的对象(可能是致命的).

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

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

更详细地说,自动释放池表现为线程局部堆栈 - 您可以推送和弹出,但在该线程上的任何内容被自动释放之前应始终存在一个.自动释放消息不会从一个线程传输到另一个线程.

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

无论如何,不​​是猜测何时创建自动释放池,而只是了解创建它们的位置以及何时应该创建它们.这一切都很明确 - 没有必要进行猜测,也没有必要担心创造它们.

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

即使是Cocoa应用程序中的主线程也需要自动释放池 - 它通常不是您编写的内容,因为它存在于项目模板中.

更新 - 调度队列

为了回应更新的问题:是的,您仍然应该为在调度队列下运行的程序创建自动释放池 - 请注意,使用调度队列,您不会创建线程,因此这与原始问题完全不同.原因:尽管调度队列确实管理自动释放池,但不保证它们被清空的时间/点.也就是说,您的对象将被释放(在某些时候),但您也应该在此上下文中创建自动释放池,因为实现可以(理论上)每运行10,000个块或大约每天耗尽池.所以在这种情况下,在你最终消耗太多内存,或者你的程序期望它的对象将以某种确定的方式被破坏的情况下,它实际上只是致命的 - 例如,你可能正在加载或处理图像如果由于自动释放池而导致这些图像的寿命意外延长,那么背景和最终消耗大量内存.另一个示例是共享资源或全局对象,您可以在其中响应通知或引入竞争条件,因为"阻止本地"对象可能比您预期的要长得多.还要记住,实现/频率可以随着它的实现者认为合适而自由改变.

  • @JimThio我觉得你误解了; 我没有说GCD没有创建线程,我说*你*没有创建线程.GCD调度队列的操作更像线程池而不是线程; 它不会为您提交的每个任务生成新线程.是的,GCD将在幕后创建和管理线程,但机制(很大程度上)*从你的*中抽象出来.设置自己明确创建的线程(例如使用pthreads或NSThread)时所经历的步骤是不同的场景/过程.这是一个重要的区别,因为自动释放池是线程本地的. (6认同)
  • @JimThio*"...... GCD将自己创建自动释放池"*正确.*"只要我使用GCD,我就不需要创建自己的自动释放池."*嗯,不,那不是我在**Update - Dispatch Queues**中写的.我鼓励你创建它们,即使你实际上不需要*在绝大多数情况下创建它们.问题是您无法动态确定何时不需要它们.很多人对98%的报道感到满意,因此不会创造它们.具有高标准的图书馆开发人员OTOH可能*始终*创建它们. (5认同)