在ARC下,是否仍建议为循环创建@autoreleasepool?

19

假设我有一个循环,返回一堆自动释放的NSData对象...

NSData* bigData = ...
while(some condition) {
    NSData* smallData = [bigData subdataWithRange:...];
    //process smallData
}

在 ARC 下,我是否仍需要在 while 循环条件周围包装一个 @autoreleasepool 块?

NSData* bigData = ...
@autoreleasepool {
    while(some condition) {
        NSData* smallData = [bigData subdataWithRange:...];
        //process smallData
    }
}
我问的原因是,对于调用dataWith...方法的NSData对象,我发现仪器中的实时分配计数飙升了。而对于initWith...方法,实时分配计数要少得多。 如果可能的话,最好选择initWith...方法吗?
3个回答

13

在紧密循环中使用便捷方法时,仍应该使用自动释放池。在ARC下,所有旧的内存管理规则仍然适用,编译器只是为您注入了RRs。请查看伟大的Mike Ash的帖子!

链接


10
根据@Chuck的答案:为了发挥作用,@autoreleasepool需要放在循环内部。惯用法是 while (x) @autoreleasepool { ... },而不是 @autoreleasepool { while (x) { ... } } - Quuxplusone
这个说法过于简化并且不正确。ARC 经常可以优化掉对 autorelease 池的使用,特别是对于返回 +0 对象的方法(大多数情况下都是使用 autorelease)。 - Steven Fisher

13

我认为你的问题在于自动释放池应该放在循环内部。如果将循环放在自动释放块内而不是反之,则累积的对象直到循环结束后才会被释放。


我从没想过把 @autoreleasepool 放在循环里面...谢谢你的提示。 - Tim Reddy
如果不使用@autorelease块,并且考虑到smallData是一个局部变量,那么在while循环的每次迭代之后,指向该局部变量的对象是否被释放?为什么我们需要@autorelease块?这让我感到困惑。 - CarlosAndres

7
在ARC下,我是否仍应该在while条件周围加上@autoreleasepool?
是的。自动释放池仍然存在,并且与以前一样增长和弹出。当启用ARC时,编译器只是根据TU可见的方法和默认命名约定添加和合并必要的保留和释放操作(回应Logan)。
在ARC中的执行方式几乎与手动引用计数相同:自动释放池栈仍然存在。一个区别是编译器可能会以与您编写的方式略有不同的顺序执行引用计数操作(但不是错误的方式),并可能省略不必要的保留循环。
是否最好尽可能使用initWith...方法?
就最小化与自动释放副本相比堆内存增长而言:是的。这一直是事实。这在内存非常有限的iOS设备上尤为重要。
唯一的例外是当对象可以避免分配时。例如:
NSString * copy = [NSString stringWithString:arg];

在这种情况下,copy 可能是 [[arg retain] autorelease]。请注意,在这种情况下,copy 仍然是自动释放的,但通常不需要费太大力气来测试此类优化的存在。注意:最好使用 copy = [arg copy]...[arg release]

另一个好处是,如果对象从未被自动释放,那么您的引用计数不平衡往往会更早地被发现,并且更接近调用点(而不是在 Autorelease Pool 最终弹出时)。

对于大型自动释放池,性能实际上比大多数人想象的要差得多。如果您可以避免过度依赖它们(例如使用 alloc+init...+release),则可以使程序明显加快。显式创建自动释放池是廉价的,并且可以帮助最小化此问题。当分配很大和/或数量很多时,请尽可能避免在它们上面使用 autorelease,并将这些部分包装在显式自动释放池中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接