带有 NSAutoreleasePool 的嵌套 dispatch_async 中的 EXC_BAD_ACCESS

Posted

技术标签:

【中文标题】带有 NSAutoreleasePool 的嵌套 dispatch_async 中的 EXC_BAD_ACCESS【英文标题】:EXC_BAD_ACCESS in nested dispatch_async with an NSAutoreleasePool 【发布时间】:2012-01-20 17:35:31 【问题描述】:

我有一些类似于以下代码的代码:

dispatch_queue_t queue          = dispatch_queue_create("", 0);
dispatch_queue_t inner_queue    = dispatch_queue_create("", 0);
dispatch_async(queue,
^
    NSAutoreleasePool* autoreleasePool = [[NSAutoreleasePool alloc] init];
    NSArray* objects = [self.otherObject getObjectsFromSlowQuery];

    [objects enumerateObjectsWithUsingBlock:^(id anObject, NSUInteger idx, BOOL *stop) 
    
        [anObject prepare];
        dispatch_async(inner_queue,
        ^
            InnerObject* innerObject = anObject.innerObject;
            [self.helper doSomethingExpensiveWithObject:innerObject];
        );
        dispatch_sync(self.syncQueue,
        ^
             [self insertIntoCollection:anObject];
        );
    ];
    dispatch_release(inner_queue);
    [autoreleasePool drain];
);
dispatch_release(queue);

其中[anObject.innerObject]nonatomic 属性。

当我尝试在doSomethingExpensiveWithObject: 调用中访问innerObject 的属性时,我收到了来自用户的崩溃报告,其中显示objc_msgSend() 中的EXC_BAD_ACCESS

起初我在想autoreleasePool 可能已经耗尽,所以innerObject 实例在从doSomethingExpensiveWithObject: 返回之前被释放,但据我所知anObject 应该由内部dispatch_async 调用保留还应该保持innerObject 活着。

我错过了什么?

【问题讨论】:

代码在没有队列的情况下可以工作吗?另外,你don't need to allocate an NSAutoreleasePool在这里。 块不会影响它们捕获的对象的保留计数。 @user1139069: They do. 这就是为什么需要__block 来关闭它(并使块能够修改变量)。 @user1139069 dispatch_async 调用 Block_copy 将变量保留在块范围内。 没有特别证据表明自动释放池与崩溃有关。但是使用dispatch_async 意味着该块可能在具有自己的自动释放池的其他线程上运行(在每个块运行后可能不会被耗尽)。因此,如果您认为 doSomethingExpensiveWithObject: 需要它,您应该在 inner_queue 块内创建/排出一个池。 【参考方案1】:

仪器可以快速解决这个问题 - 与僵尸一起运行并在它停止时查看引用计数。

【讨论】:

我无法重现这个错误,所以现在运行带有僵尸的仪器没有帮助。

以上是关于带有 NSAutoreleasePool 的嵌套 dispatch_async 中的 EXC_BAD_ACCESS的主要内容,如果未能解决你的问题,请参考以下文章

iPhone:关于 NSAutoreleasePool 的困惑

如何使用 NSAutoreleasePool

NSAutoReleasePool 泄漏

NSAutoreleasePool 和 @autoreleasepool 块有啥区别?

在没有 NSAutoReleasePool 的情况下使用 autoReleased 对象?

Instruments 中的 NSAutoreleasePool 泄漏