【问题标题】:Closure variables not deallocating闭包变量不释放
【发布时间】:2014-12-17 09:26:40
【问题描述】:

我描述问题的最简单方法是用一个小例子来展示。

//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 对象之后才被释放。预期的行为肯定是在每次关闭调用后释放内存?

【问题讨论】:

  • 没有。您的循环“数千次”将调用数千个该块,这些块将使用数千个相同的分配对象加载相同的变量数千次,并将数千个相同的帧推入堆栈。你是需要对记忆更加保守的人!
  • @CodaFi 从设计层面来看,我该如何解决这个问题?使用解析块非常优雅。有没有办法解决内存问题?

标签: ios objective-c xcode memory-management swift


【解决方案1】:

如果实例化自动释放对象,但不会定期耗尽自动释放池,则可能会出现此类问题。通常,直到您返回到运行循环(或操作或分派的任务完成),池才会被耗尽。因此,您总是必须非常小心地循环数千次。 (请参阅Advanced Memory Management Programming Guide: Using Autorelease Pool Blocks使用本地自动释放池块来减少峰值内存占用部分。)

通常通过创建(从而耗尽)您自己的本地自动释放池来控制此峰值内存使用量:

- (void)startParsing {

    // loop around thousands of times

    for ( ... ) {  
        @autoreleasepool {
            // do whatever

            self.callbackBlock(someNewObject)
        }
    }    
}

还有一个等效的 Swift 函数,也毫不奇怪地称为 autoreleasepool(),所以如果您知道自动释放对象是由您的闭包创建的东西创建的,那么您也可以在那里处理它。如果没有在 Instruments 中查看代码或对其进行分析,很难猜测是哪个创建了自动释放对象。 (注意,是的,我知道原生 Swift 对象通常不会自动释放,但你不能保证 Swift 闭包调用的任何代码,这就是 Swift 提供 autoreleasepool 函数的原因。)

如果你真的想诊断这个问题,你可以在 Instruments 中运行它,并在 startParsing 完成之前暂停它,查看尚未发布的内容,然后返回到这些对象被实例化的位置,然后将帮助您诊断创建自动释放对象的位置,从而确认您需要在哪里添加池。

显然,在处理大循环时,除了自动释放对象(例如在内存中同时持有太多大型资产(图像等)、递归调用函数)之外,还有其他此类内存问题的来源, 等等。)。但我假设您已经查看了您的代码以了解任何明显的类似内容。所以自动释放对象是另一件需要检查的事情。

【讨论】:

猜你喜欢
  • 2018-10-03
  • 1970-01-01
  • 1970-01-01
  • 2012-05-07
  • 1970-01-01
  • 1970-01-01
  • 2013-01-03
  • 2013-02-09
  • 2011-01-26
相关资源
最近更新 更多