例如,假设您有一个
NSArray
包含大量项目,可能需要很长时间才能解除分配。你需要访问
不可变数组
在主线程上,但一旦处理完它,就可以在后台队列中取消分配它。后台块只需要捕获阵列,然后立即解除分配。它实际上与它没有任何关系。编译器能否检测到这一点,并“错误地”跳过块捕获?
例子:
// On the main thread...
NSArray *outgoingRecords = self.records;
self.records = incomingRecords;
dispatch_async(background_queue, ^{
(void)outgoingRecords;
// After this do-nothing block exits, then outgoingRecords
// should be deallocated on this background_queue.
});
outgoingRecords
将始终在该块中捕获,并始终在
background_queue
?
我将添加更多的上下文来更好地说明我的问题:
后台读取完成后,我跳转到主线程交换Objective-C对象并重新填充表。
在这一点上,我根本不关心旧向量或其父Objective-C类的内容。没有什么奇特的析构函数或对象图可以拆卸,但释放数百兆字节甚至千兆字节的内存并不是瞬间的。所以我愿意把它放到一个后台队列中,并在那里进行内存释放。在我的测试中,这似乎工作得很好,在16毫秒过去之前,我在主线程上有更多的时间做其他事情。
count
)因此编译器无法以某种方式对其进行优化。
这是另一个不使用调度队列但仍然使用块的场景,这是我真正感兴趣的部分。
id<MTLCommandBuffer> commandBuffer = ...
// A custom class that manages an MTLTexture that is backed by an IOSurface.
__block MyTextureWrapper *wrapper = ...
// Issue some Metal calls that use the texture inside the wrapper.
// Wait for the buffer to complete, then release the wrapper.
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> cb) {
wrapper = nil;
}];
MTLTexture
进入正在循环的像素池。IOSurface正在进程之间共享,而且,据我所知,
MTLTexture
不会增加曲面上的使用计数。我的包装器类可以。当我的包装器类被释放时,useCount被递减,然后缓冲池可以自由地回收IOSurface。
这一切都如预期的那样工作,但我最终得到了上面这样愚蠢的代码,只是因为不确定是否需要在块中“使用”包装器实例以确保它被捕获。如果包装器在完成处理程序运行之前被解除分配,那么IOSurface将被回收,纹理将被覆盖。