测试代码1:
// 测试的次数 size_t count = 10; // 循环中产生的实例的个数 NSUInteger objectCount = 10000000; // 测试1 - @autoreleasepool在循环外部 // 在循环中产生的之后不再被使用的实例需要在整个for循环结束后才会被调用release方法 // 实际测试中,内存占用的峰值为480M,平均耗时为10780423522纳秒 uint64_t time1 = dispatch_benchmark(count, ^{ @autoreleasepool { for (NSUInteger i = 0; i < objectCount; ++i) { [NSString stringWithFormat:@"str - %lu", (unsigned long)i]; } } }); NSLog(@"@autoreleasepool { for { } } = %llu ns", time1);
测试代码2:
// 测试的次数 size_t count = 10; // 循环中产生的实例的个数 NSUInteger objectCount = 10000000; // 测试2 - @autoreleasepool在循环内部 // 在循环中产生的之后不再被使用的实例将代码执行到@autoreleasepool代码块的第二个括号时被调用release操作 // 实际测试中,内存占用的峰值为16M,平均耗时为9902072437纳秒 uint64_t time2 = dispatch_benchmark(count, ^{ for (NSUInteger i = 0; i < objectCount; ++i) { @autoreleasepool { [NSString stringWithFormat:@"str - %lu", (unsigned long)i]; } } }); NSLog(@"for { @autoreleasepool { } } = %llu ns", time2);
总结:
根据Apple文档的建议,如果在一个循环中产生了大量的临时对象,可以通过在循环内部提供一个自动释放池在下一次迭代之前来清除这些对象,以减少最大内存占用。
测试代码2演示了这种情况下@autoreleasepool代码块正确的使用方式,即放在循环内部。
对照测试表明将@autoreleasepool代码块放在循环内部并没有比放在循环外部性能低,实际上两种情况效率相差不大。但只有测试代码2演示的编码方式才是正确的。