Question

I was recently reading the Advanced Memory Management documentation when I stumbled upon the Autorelease Pool Blocks. The documentation states:

You may use an autorelease pool block inside a loop to dispose of those objects before the next iteration. Using an autorelease pool block in the loop helps to reduce the maximum memory footprint of the application.[...] Any object sent an autorelease message inside the autorelease pool block is released at the end of the block.

What about the objects created inside the block that don't get an autorelease call? I assume they also get their retain count decremented to 0. Then, my question is, what's the point of calling autorelease when either the way, the objects created inside the block will get a release call at the end of the block?

Était-ce utile?

La solution

An object can be released by sending it a -release or -autorelease message.

With -release the reference count is immediately decremented which may lead to a deallocation.

With -autorelease the decrement is deferred to keep an object alive beyond the scope in which it was created. For example, a helper method -createFoo may return an autoreleased object so that callers can use the returned object without it being immediately deallocated on return from the method, and without having to worry about who is responsible for releasing it.

With ARC, the compiler handles all these details for you. All you need to know is that sometimes objects are kept alive a little longer using autorelease.

This 'keeping alive' behaviour has implications for loops like the following:

- (void)foobar
{
    for (/* a long time */) {
        NSMutableString *s = [NSMutableString string];
        // ...
    }
}

The +string method on NSMutableString will return an autoreleased object. This is not automatically deallocated at the end of the loop iteration or method (well, ARC can do some clever optimizations by looking at the call stack, but we will ignore this). This means you will get unbounded memory growth while you are inside the loop body.

Note that if we had used the following:

NSMutableString *s = [[NSMutableString alloc] init];

then ARC would insert a release call at the end of the loop body and the string would be immediately released.

To work around the unbounded memory growth of the first example, you define an explicit autorelease pool:

- (void)foobar
{
    for (/* a long time */) {
        @autoreleasepool {
            NSMutableString *s = [NSMutableString string];
            // ...
        }
    }
}

Now, after each iteration of the loop, the autorelease pool is destroyed and any objects that were autoreleased inside the pool (including our string) will be released immediately.

So it all depends on the kinds of methods you are calling and whether they are returning autoreleased objects.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top