< Previous PageNext Page > Hide TOC

Autorelease Pools

This document contains information on fine-tuning your application’s handling of autorelease pools; see the document “Object Ownership and Disposal” for general information on using the autorelease mechanism.

Contents:

Overview of Autorelease Pools
Autorelease Pools in Non-AppKit Programs
Autorelease Pools and Threads
Scope of Autorelease Pools and Implications of Nested Autorelease Pools
Guaranteeing the Foundation Ownership Policy
Garbage Collection


Overview of Autorelease Pools

An autorelease pool is an instance of NSAutoreleasePool that “contains” other objects that have received an autorelease message; when the autorelease pool is deallocated it sends a release message to each of those objects. An object can be put into an autorelease pool several times, and receives a release message for each time it was put into the pool. Thus, sending autorelease instead of release to an object extends the lifetime of that object at least until the pool itself is released (the object may survive longer if it is retained in the interim).

Cocoa always expects there to be an autorelease pool available. If a pool is not available, autoreleased objects do not get released and you leak memory. If you send an autorelease message when a pool is not available, Cocoa logs a suitable error message.

You create an NSAutoreleasePool object with the usual alloc and init messages, and dispose of it with release or drain (an exception is raised if you send autorelease or retain to an autorelease pool)—to understand the difference between release or drain, see “Garbage Collection.” An autorelease pool should always be released in the same context (invocation of a method or function, or body of a loop) in which it was created.

Autorelease pools are arranged in a stack, although they are commonly referred to as being "nested." When you create a new autorelease pool, it is added to the top of the stack. When pools are deallocated, they are removed from the stack. When an object is sent an autorelease message, it is added to the current topmost pool for the current thread.

The ability to nest autorelease pools means that you can include them in any function or method. For example, a main function may create an autorelease pool and call another function that creates another autorelease pool. Or a single method might have an autorelease pool for an outer loop, and another autorelease pool for an inner loop. The ability to nest autorelease pools is a definite advantage, but there are side effects when exceptions occur (see “Scope of Autorelease Pools and Implications of Nested Autorelease Pools”).

The Application Kit automatically creates a pool at the beginning of an event cycle (or event-loop iteration), such as a mouse down event, and releases it at the end, so your code normally does not have to worry about them. There are three cases, though, where you might create and destroy your own autorelease pools:

Autorelease pools are used "in line". There should typically be no reason why you should make an autorelease pool an instance variable of an object.

Autorelease Pools in Non-AppKit Programs

Enabling the autorelease mechanism in a program that is not based on the Application Kit is easy. You can simply create an autorelease pool at the beginning of the main() function, and release it at the end—this is the pattern used by the Foundation Tool template in Xcode. This establishes a pool for the lifetime of the task. However, this also means that any autoreleased objects created during the lifetime of the task are not disposed of until the task completes. This may lead to the task's memory footprint increasing unnecessarily. You can also consider creating pools with a narrower scope.

Many programs have high-level loops where they do much of their work. To enable the autorelease mechanism you can create an autorelease pool at the beginning of an iteration through this loop and release it at the end.

Your main function might look like the code in Listing 1.

Listing 1  Example of a main function for a non-AppKit program

void main()
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
    NSArray *args = [[NSProcessInfo processInfo] arguments];
    unsigned count, limit = [args count];
 
    for (count = 0; count < limit; count++)
    {
        NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
        NSString *fileContents;
        NSString *fileName;
 
        fileName = [args objectAtIndex:count];
        fileContents = [[[NSString alloc] initWithContentsOfFile:fileName] autorelease];
        // this is equivalent to using stringWithContentsOfFile:
 
        /* Process the file, creating and autoreleasing more objects. */
 
        [loopPool release];
    }
 
    /* Do whatever cleanup is needed. */
    [pool drain];
 
    exit (EXIT_SUCCESS);
}

This program processes files passed in on the command line. The for loop processes one file at a time. An NSAutoreleasePool object is created at the beginning of this loop and released at the end. Therefore, any object sent an autorelease message inside the loop (such as fileContents) is added to loopPool, and when loopPool is released at the end of the loop those objects are also released. Additionally, any autoreleased objects created in the context of the for loop (such as fileName) are released when loopPool is released even if they’re not explicitly sent an autorelease message.

Autorelease Pools and Threads

Each thread in a Cocoa application maintains its own stack of NSAutoreleasePool objects. When a thread terminates, it automatically releases all of the autorelease pools associated with itself. Autorelease pools are automatically created and destroyed in the main thread of applications based on the Application Kit, so your code normally does not have to deal with them there. If you are making Cocoa calls outside of the Application Kit's main thread, however, you need to create your own autorelease pool. This is the case if you are writing a Foundation-only application or if you detach a thread.

If your application or thread is long-lived and potentially generates a lot of autoreleased objects, you should periodically destroy and create autorelease pools (like the Application Kit does on the main thread); otherwise, autoreleased objects accumulate and your memory footprint grows. If your detached thread does not make Cocoa calls, you do not need to create an autorelease pool.

Note: If you create secondary threads using the POSIX thread APIs instead of NSThread, you cannot use Cocoa—including NSAutoreleasePool—unless Cocoa is in multithreading mode. Cocoa enters multithreading mode only after detaching its first NSThread object. To use Cocoa on secondary POSIX threads, your application must first detach at least one NSThread object, which can immediately exit. You can test whether Cocoa is in multithreading mode with the NSThread class method isMultiThreaded.

Scope of Autorelease Pools and Implications of Nested Autorelease Pools

It is common to speak of autorelease pools as being nested because of the enclosure evident in code, as illustrated in Listing 1. But you can also think of nested autorelease pools as being on a stack, with the “innermost” autorelease pool being on top of the stack. As noted earlier, this is actually how nested autorelease pools are implemented: Each thread in a program maintains a stack of autorelease pools. When you create an autorelease pool, it is pushed onto the top of the current thread’s stack. When an object is autoreleased—that is, when an object is sent an autorelease message or when it is passed as the argument to the addObject: class method—it is always put in the autorelease pool at the top of the stack.

The scope of an autorelease pool is therefore defined by its position in the stack and the simple fact of its existence. The topmost pool is the pool to which autoreleased objects are added. If another pool is created, the current topmost pool effectively goes out of scope until the new pool is released (at which point the original pool once again becomes the topmost pool). It (obviously) goes out of scope permanently when it is itself released.

If you release an autorelease pool that is not the top of the stack, this causes all (unreleased) autorelease pools above it on the stack to be released, along with all their objects. If you neglect to send release to an autorelease pool when you are finished with it (something not recommended), it is released when one of the autorelease pools in which it nests is released.

This behavior has implications for exceptional conditions. If an exception occurs, and the thread suddenly transfers out of the current context, the pool associated with that context is released. However, if that pool is not the top pool on the thread’s stack, all the pools above the released pool are also released (releasing all their objects in the process). The top autorelease pool on the thread’s stack then becomes the pool previously underneath the released pool associated with the exceptional condition. Because of this behavior, exception handlers do not need to release objects that were sent autorelease. Neither is it necessary or even desirable for an exception handler to send release to its autorelease pool, unless the handler is re-raising the exception.

Guaranteeing the Foundation Ownership Policy

By creating an autorelease pool instead of simply releasing objects, you extend the lifetime of temporary objects to the lifetime of that pool. After an autorelease pool is deallocated, you should regard any object that was autoreleased while that pool was active as “disposed of”, and not send a message to that object or return it to the invoker of your method.

If you must use a temporary object beyond an autorelease context, you can do so by sending a retain message to the object within the context and then send it autorelease after the pool has been released as in:

– findMatchingObject:anObject
{
    id match = nil;
 
    while (match == nil) {
        NSAutoreleasePool *subPool = [[NSAutoreleasePool alloc] init];
 
        /* Do a search that creates a lot of temporary objects. */
        match = [self expensiveSearchForObject:anObject];
 
        if (match != nil) {
            [match retain]; /* Keep match around. */
        }
        [subPool release];
    }
 
    return [match autorelease];   /* Let match go and return it. */
}

By sending retain to match while subpool is in effect and sending autorelease to it after subpool has been released, match is effectively moved from subpool to the pool that was previously active. This extends the lifetime of match and allows it to receive messages outside the loop and be returned to the invoker of findMatchingObject:.

Garbage Collection

Although the garbage collection system (Garbage Collection Programming Guide) does not use autorelease pools per se, autorelease pools can be useful in providing hints to the collector if you are developing a hybrid framework (that is, one that may be used in garbage-collected and reference-counted environments).

Autorelease pools are released when you want to relinquish ownership of the objects that have been added to the pool. This frequently has the effect of disposing of temporary objects that have accumulated up to that point—for example, at the end of the event cycle, or during a loop when you create a large number of temporary objects. These are typically also points at which it might be useful to hint to the garbage collector that collection is likely to be warranted.

In a garbage collected environment, release is a no-op. NSAutoreleasePool therefore provides a drain method that in a reference-counted environment behaves the same as calling release, but which in a garbage collected environment triggers garbage collection (if the memory allocated since the last collection is greater than the current threshold). Typically, therefore, you should use drain rather than release to dispose of an autorelease pool.



< Previous PageNext Page > Hide TOC


© 2009 Apple Inc. All Rights Reserved. (Last updated: 2009-05-06)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.