我正在尝试使用有限差分方法为物理项目实现建模类,以模拟简单的钟摆。我希望能够使这个类尽可能通用,这样我就能用方法的每次迭代的值做任何我想做的事情。出于这个原因,我给了我的方法回调块,如果我们想要的话,它也可以用来停止方法。
例如,我的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
阻止就会立即下降。无论如何,我可以保持这个不错的功能,没有大量的内存问题吗?
答案 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;
}