2014-10-22 111 views
2

我最简单的描述问题的方法是用一个小例子来显示。未关闭变量的关闭变量

//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

不会。您的循环“成千上万次”将调用数千个该块,这些块将使用数千个相同的分配对象加载相同的变量数千次,并将数千个相同的帧推入堆栈。你是一个需要更加保守的记忆! – CodaFi 2014-10-22 02:37:01

+0

@CodaFi从设计层面上来说,我该如何解决这个问题?使用解析块非常优雅。有没有办法解决内存问题? – 2014-10-22 03:06:02

回答

1

如果一个实例化autorelease对象,但不会定期排空autoreleasepool,则会出现此类问题。一般情况下,只有在您退回到运行循环(或操作或分派的任务完成)之前,池才会被排空。因此,你总是必须非常小心循环数千次。 (见使用本地autorelease池块来降低Advanced Memory Management Programming Guide: Using Autorelease Pool Blocks的峰值内存占用部分。)

一个通常通过创建(并由此排出)控制该峰值内存使用您自己的本地autoreleasepool:

- (void)startParsing { 

    // loop around thousands of times 

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

      self.callbackBlock(someNewObject) 
     } 
    }  
} 

还有一个等价的Swift函数,不出意外地叫做autoreleasepool(),所以如果你知道autorelease对象是由你的闭包创建的东西创建的,那么你也可以在那里解决它。如果没有在Instruments中查看代码或分析代码,很难猜测哪个是创建autorelease对象。 (注意,是的,我知道Swift本地对象通常不是自动发布的,但是不能担保Swift收到的任何代码,这就是Swift提供autoreleasepool函数的原因。)

如果您确实想要诊断这一点,你可以在Instruments中运行它,并在startParsing完成之前暂停它,并查看尚未发布的内容,然后返回到实例化这些对象的位置,这将有助于诊断创建autorelease对象的位置,从而确认您需要添加池的位置。显然,在处理大循环时,除了autorelease对象之外,还有其他这类内存问题的来源(例如,同时在内存中保存太多大型资源(图像等),递归调用功能等)。但是我认为你已经检查过你的代码,看看有没有这样的事情。所以autorelease对象是另一件要检查的事情。

+0

工程就像一个魅力。感谢您的深入介绍,非常感谢。 – 2014-10-22 03:21:57