带有 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 和 @autoreleasepool 块有啥区别?