Objective-c摆锤建模记忆问题

时间:2013-11-08 23:31:11

标签: objective-c memory-leaks simulation

我正在尝试使用有限差分方法为物理项目实现建模类,以模拟简单的钟摆。我希望能够使这个类尽可能通用,这样我就能用方法的每次迭代的值做任何我想做的事情。出于这个原因,我给了我的方法回调块,如果我们想要的话,它也可以用来停止方法。

例如,我的Euler方法循环如下所示:

for (NSInteger i = 0; i < n; i++) {

    if (callBack) {
        if(!callBack(NO, currentTheta, currentThetaDot, currentT, (CGFloat)i/n)) break;
    }

    currentTheta += self.dt*f_single_theta(currentThetaDot);
    currentThetaDot += self.dt*f_single_thetaDot(currentTheta, currentThetaDot, gamma);

    currentT += self.dt;

}

在callBack块中我运行代码

^BOOL (BOOL complete, double theta, double thetaDot, CGFloat timeElapsed, CGFloat percentComplete){

    eulerT = [eulerT stringByAppendingFormat:@"%.8f\n",timeElapsed];
    eulerTheta = [eulerTheta stringByAppendingFormat:@"%.8f\n",theta];

    if ((currentThetaDot*currentThetaDot + cos(currentTheta)) > 0.5) {
        return 0; // stops running if total E > 0.5
    }        

    return 1;

}];

其中eulerT和eulerTheta是我后来保存到文件中的字符串。这种回调方法很快就会导致大量内存,即使是订单数为n的n,我最终也会占用大约1Gb的内存。一旦我发表评论,呼叫callBack阻止就会立即下降。无论如何,我可以保持这个不错的功能,没有大量的内存问题吗?

2 个答案:

答案 0 :(得分:2)

您应该将循环内部包装在@autoreleasepool {}中以清理临时对象。

答案 1 :(得分:2)

许多不熟悉Objective C的人都没有意识到[NSArray array][[NSArray alloc] init]之间的区别。在ARC之前的日子里,差异现在更加明显。两者都创建一个新对象,但前者分配对象,将其分配给当前NSAutoreleasePool,并保留计数为0,而后者分配它并使其保留计数为1。

当保留计数达到0时,分配给NSAutoreleasePool的对象不会立即解除分配。相反,当操作系统有时间时,它们会被释放。通常,这可以假设为控制返回到当前运行循环,但也可以是drain上调用NSAutoreleasePool时。

使用ARC,差异不太明显,但仍然很重要。您分配的许多(如果不是大多数)对象被分配给自动释放池。这意味着你不会因为你已经完成使用它们而得到它们。这会导致内存使用量紧张,例如您发布的内容。解决方案是明确地消耗自动释放池,如下所示:

for (NSInteger i = 0; i < n; i++) {

    if (callBack) {
        @autoreleasepool {
            if(!callBack(NO, currentTheta, currentThetaDot, currentT, (CGFloat)i/n))
                break;
        }
    }

    currentTheta += self.dt*f_single_theta(currentThetaDot);
    currentThetaDot += self.dt*f_single_thetaDot(currentTheta, currentThetaDot, gamma);

    currentT += self.dt;

}