我描述问题的最简单方法是用一个小例子来展示。
//In a swift file
myObjectiveCObject.setCallbackBlock {(object: AnyObject!) -> Void in
var chunkOfMemory = //fill up var with memory stuff. Self is never referenced.
}
myObjectiveCObject.startParsing()
//In the objective-c class file
@property (nonatomic, copy) MyBlockType callbackBlock;
- (void)startParsing {
//loop around thousands of times calling
self.callbackBlock(someNewObject)
}
在完成objective-c对象之前,每个闭包调用分配的内存都不会被释放。当然,预期的行为是在每次闭包调用后释放内存吗?
答案 0 :(得分:1)
如果一个实例化自动释放对象,但不定期排出自动释放池,则会出现这种问题。通常,在您回退到运行循环(或操作或调度任务完成)之前,池不会被耗尽。因此,您总是必须非常小心地循环数千次。 (参见{em>使用本地自动释放池块来减少峰值内存占用部分{/ 3}}。)
通常通过创建(从而耗尽)您自己的本地自动释放池来控制此峰值内存使用量:
- (void)startParsing {
// loop around thousands of times
for ( ... ) {
@autoreleasepool {
// do whatever
self.callbackBlock(someNewObject)
}
}
}
有一个等效的Swift函数,不出所料地称为autoreleasepool()
,所以如果你知道自动释放对象是由你的闭包创建的东西创建的,你也可以在那里解决它。没有看到代码或在Instruments中分析代码,很难猜出哪个是创建自动释放对象。 (注意,是的,我知道原生的Swift对象通常不会被自动释放,但你无法保证Swift闭包调用的任何代码,这就是Swift提供autoreleasepool
函数的原因。)< / p>
如果你真的想要诊断它,可以在Instruments中运行它,并在startParsing
完成之前暂停它,并查看尚未发布的内容,并回溯到这些对象的位置实例化,这将有助于您诊断自动释放对象的创建位置,从而确认您需要添加池的位置。
显然,在处理大型循环时,除了自动释放对象(例如,同时在内存中保存太多大型资源(图像等))之外,还存在这些类型的内存问题的其他来源,递归调用函数等)。但我认为你已经检查过你的代码,看看那些明显的代码。所以自动释放对象是另一件需要检查的事情。