dispatch_async 和 autoreleasepool

Posted

技术标签:

【中文标题】dispatch_async 和 autoreleasepool【英文标题】:dispatch_async and autoreleasepool 【发布时间】:2014-05-15 23:08:54 【问题描述】:

我正在使用 dispatch_async,它依次调用使用 dispatch_async 的其他代码,它使用 for 循环分配至少 50 - 100 个对象。我怎么知道什么时候应该使用@autoreleasepool?我可以在分配超过 10 个对象的任何 dispatch_async 中只使用 @autoreleasepool,还是使用过多的 autoreleasepool 有风险?

【问题讨论】:

【参考方案1】:

高级内存管理编程指南的Using Autorelease Pools 部分建议在“必须这样做或这样做有益”的地方使用自动释放池。我通常不建议无缘无故地加入自动释放池,尽管您通常可以这样做而不会发生任何事故。

@autoreleasepool 不是必需的,除非您正在处理自己的 NSThread 实例(您在这里没有这样做),或者如果您正试图显式降低由于使用许多自动释放对象而导致的高水位线。

在确定何时需要自动释放池以降低峰值内存利用率时,这并不像“我有十个对象”那么简单。这是对象大小的问题,现在你有很多。如果处理大图像(例如 20000 x 20000 像素),那么一张以上的图像可能太多了。如果处理小对象(字符串、数字等),那么您可以拥有数千个对象而不会造成问题。它只适用于你使用自动释放对象的地方。

因此,我建议您采用一种经验方法,在这种方法中,您可以考虑 (a) 在您的例行程序使用的最大内存量; (b) 您正在使用多少个自动释放对象,并从那里做出决定。

但值得注意的是,在某些孤立的情况下,必须小心添加自动释放池。典型的例子是你有一个 NSError ** 参数到一个方法,如果有一些错误你传回一个对象。比如这段代码就有问题:

/** Some method that will optionally return error object.
 *
 *  @param  error  The error object being returned
 *
 *  @return        This returns an NSData if successful, and `nil` upon error.
 *                 See NSError object to determine why it failed.
 */

- (NSData *)someMethod:(NSError * __autoreleasing *)error

    @autoreleasepool 

        // do some stuff

        // following line is wrong as the error will be released when pool is drained 

        if (failure)
            *error = [NSError errorWithDomain:kMyAppDomain code:code userInfo:nil];

        // etc
    

在这种情况下,您可以像这样重构它:

- (NSData *)someMethod:(NSError * __autoreleasing *)error

    NSError *localError;

    @autoreleasepool 

        // do some stuff

        // save it in some local variable outside of the scope of this block

        if (failure) 
            localError = [NSError errorWithDomain:kMyAppDomain code:code userInfo:nil];
        
    

    // now you can return it safely
    *error = localError;

    // etc

【讨论】:

为了完整起见,使用不必要的自动释放池有什么本质上的错误吗?如果插入多个位置,它们是否有任何性能拖累? 通常这不是问题,但如果您要返回自动释放对象(典型示例是方法有NSError ** 参数),则会出现问题。我只是犹豫了,因为我在 Stack Overflow 中看到太多答案,这些答案在不了解您为什么以及在哪里这样做的情况下,用“哦,扔一个@autoreleasepool”轻松地回答任何内存问题。 那么 dispatch_async 呢?需要在里面使用@autoreleasepool吗? @poGUIst - 如果您使用调度队列或操作队列,则不需要自动释放池。只有在 (a) 您手动分离 NSThread 或调用 performSelectorInBackground 时,您才创建自动释放池;或者 (b) 你有循环的代码,使用自动释放的对象消耗大量内存,并且你想更频繁地耗尽你的池以最小化最大内存使用(即你不想等到你让出到运行循环或分派的代码块完成)。【参考方案2】:

冒着不能完全提供帮助的风险......

当 Instruments 的分配模板显示您在特定工作流程中的内存使用显着推高了应用程序的高水位线(使用自动释放的对象)时,您应该添加 @autoreleasepools。

换句话说,避免过早优化。

【讨论】:

以上是关于dispatch_async 和 autoreleasepool的主要内容,如果未能解决你的问题,请参考以下文章

dispatch_async 和 peformSelectorInBackground 的区别

主队列上的 performSelectorOnMainThread: 和 dispatch_async() 有啥区别?

(iOS) dispatch_async() 与 NSOperationQueue

dispatch_sync和dispatch_async的区别

dispatch_async 影响以下代码的性能?

了解 dispatch_async