【发布时间】:2012-03-29 08:11:58
【问题描述】:
我在一个 iPad 应用程序上工作,它有一个同步过程,它在一个紧密的循环中使用 Web 服务和 Core Data。为了根据Apple's Recomendation 减少内存占用,我会定期分配和耗尽NSAutoreleasePool。这目前效果很好,并且当前应用程序没有内存问题。但是,我计划转移到 NSAutoreleasePool 不再有效的 ARC,并希望保持这种相同的性能。我创建了一些示例并对它们进行了计时,我想知道使用 ARC 实现相同性能并保持代码可读性的最佳方法是什么。
出于测试目的,我提出了 3 个场景,每个场景都使用 1 到 10,000,000 之间的数字创建一个字符串。我将每个示例运行了 3 次,以确定它们使用带有 Apple LLVM 3.0 编译器(不带 gdb -O0)和 XCode 4.2 的 Mac 64 位应用程序需要多长时间。我还通过仪器运行了每个示例,以大致了解内存峰值。
以下每个示例都包含在以下代码块中:
int main (int argc, const char * argv[])
{
@autoreleasepool {
NSDate *now = [NSDate date];
//Code Example ...
NSTimeInterval interval = [now timeIntervalSinceNow];
printf("Duration: %f\n", interval);
}
}
NSAutoreleasePool Batch [Original Pre-ARC](峰值内存:~116 KB)
static const NSUInteger BATCH_SIZE = 1500;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for(uint32_t count = 0; count < MAX_ALLOCATIONS; count++)
{
NSString *text = [NSString stringWithFormat:@"%u", count + 1U];
[text class];
if((count + 1) % BATCH_SIZE == 0)
{
[pool drain];
pool = [[NSAutoreleasePool alloc] init];
}
}
[pool drain];
运行时间:
10.928158
10.912849
11.084716
外部@autoreleasepool(内存峰值:~382 MB)
@autoreleasepool {
for(uint32_t count = 0; count < MAX_ALLOCATIONS; count++)
{
NSString *text = [NSString stringWithFormat:@"%u", count + 1U];
[text class];
}
}
运行时间:
11.489350
11.310462
11.344662
内部@autoreleasepool(内存峰值:~61.2KB)
for(uint32_t count = 0; count < MAX_ALLOCATIONS; count++)
{
@autoreleasepool {
NSString *text = [NSString stringWithFormat:@"%u", count + 1U];
[text class];
}
}
运行时间:
14.031112
14.284014
14.099625
@autoreleasepool w/ goto(内存峰值:~115KB)
static const NSUInteger BATCH_SIZE = 1500;
uint32_t count = 0;
next_batch:
@autoreleasepool {
for(;count < MAX_ALLOCATIONS; count++)
{
NSString *text = [NSString stringWithFormat:@"%u", count + 1U];
[text class];
if((count + 1) % BATCH_SIZE == 0)
{
count++; //Increment count manually
goto next_batch;
}
}
}
运行时间:
10.908756
10.960189
11.018382
goto 语句提供了最接近的性能,但它使用了goto。有什么想法吗?
更新:
注意:goto 语句是@autoreleasepool 的正常退出,如documentation 中所述,不会泄漏内存。
进入时,会推送一个自动释放池。在正常退出时(休息, return、goto、fall-through 等)自动释放池被弹出。 为了与现有代码兼容,如果退出是由于异常, 自动释放池没有弹出。
【问题讨论】:
-
使用优化器。这对 ARC 代码相当重要。
-
这样
goto肯定不会,不知道,导致内存泄漏?其他一切都是有道理的:排水越少越快。无论如何,我只能评论可读性:你在任何地方都可以。那个 goto 需要一张黄色便签。 -
goto 似乎没有泄漏任何内存。看起来范围像我预期的那样耗尽了自动释放池,但我不是 ARC 专家(还)并且不想依赖 UB。
-
你不能通过反转代码并将自动释放池放在检查批量大小的
for中来做同样的事情吗?显然count必须从上次停止的地方开始...... -
@Yar 谢谢,睡眠不足让我又把事情复杂化了。
标签: objective-c ios memory-management automatic-ref-counting nsautoreleasepool