0

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

例如,我的 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;

}

在回调块中我运行代码

^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 为 10,000,我最终也会使用大约 1Gb 的 RAM。一旦我注释掉调用该callBack块,它就会立即下降。无论如何,我可以在没有大量内存问题的情况下保留这个不错的功能吗?

4

2 回答 2

2

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

当保留计数达到 0 时,分配给 an 的对象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;

}
于 2013-11-09T04:04:42.910 回答
2

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

于 2013-11-09T01:10:39.507 回答