Under ARC, is it still advisable to create an @aut

2019-01-17 20:57发布

问题:

Let's say that I have a loop that returns a bunch of autoreleased NSData objects...

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

Under ARC, should I still wrap an @autoreleasepool around the while condition?

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

The reason why I'm asking is I see the living allocation count in instruments going through the roof for my NSData objects that invoke a dataWith... method as opposed to an initWith... method. When I use initWith..., the living allocation count is much, much less.

Is it better to prefer the initWith... methods whenever possible?

回答1:

Yes you should still use autorelease pools when using convenience methods in a tight loop. All the old memory management rules still apply under ARC, the compiler is merely injecting RRs for you. Checkout the great post by the awesome Mike Ash!

Link



回答2:

I think your issue is that the autorelease pool is supposed to go inside the loop. With the loop inside the autorelease block rather than vice-versa, the accumulated objects won't be released until after the loop finishes.



回答3:

Under ARC, should I still wrap an @autoreleasepool around the while condition?

Yes. Autorelease Pools are still in place, and grow and pop as before. The compiler just adds and coalesces the necessary retains and releases operations when ARC is enabled (echoing Logan), based on the methods that are visible to the TU and default naming conventions.

Execution in ARC is nearly identical the manual reference counting: Autorelease pool stacks still exist. One difference is that the compiler may order the reference counting operations slightly different from the way you wrote it (not in an incorrect way), and may omit unnecessary retain cycles.

Is it better to prefer the initWith... methods whenever possible?

WRT minimizing heap growth compared to the autoreleased counterparts: Yes. That's always been the case. It's especially important on iOS devices, where memory is quite limited.

The exception to this is when the object may avoid an allocation. Example:

NSString * copy = [NSString stringWithString:arg];

in this case, copy may be [[arg retain] autorelease]. Note that in this case, copy is still autoreleased, but you should not usually go to great lengths to test the presence of such optimizations. Note: It's also better to use copy = [arg copy]...[arg release] here.

The other bonus is that your ref count imbalances are often caught earlier when the object is never autoreleased, and closer to the call site (rather than when the Autorelease Pool is finally popped).

Performance with large autorelease pools is actually much worse than most people would suppose. If you can avoid depending on them heavily (e.g. using alloc+init...+release), you can make your program noticeably faster. Explicitly creating autorelease pools is cheap, and can help minimize this problem. When allocations are large and/or numerous, avoid using autorelease on them where possible, and do wrap these sections in explicit autorelease pools.