Adventures in the transition from C to Cocoa.

Tuesday, June 26, 2007

NSAutoReleasePool

NSAutoReleasePool is Memory Management object used in Cocoa. They act as a catch-all for allocations, cleaning up memory when objects are no longer needed.

Instead of sticking strictly to retain and release, these pools allow us one more memory management method: autorelease. This method puts our object in the most recently-created pool. When these pools get freed, all the objects in them get freed as well. Because of this behavior, it's common to put these pools around loops and inside functions that perform several allocations. It is common to create a pool right from the beginning in main(), as a catch-all for your entire application.

Additionally, Cocoa's Frameworks often require a pool to be available for things to work correctly. Without them, the program will probably still run, but it will generate Tons of warnings like this at runtime:


cwright@phendrana:~/projects/addr>./main.broken
2007-06-26 20:43:51.068 main.broken[3819] *** _NSAutoreleaseNoPool(): Object 0x1802000 of class NSCFDictionary autoreleased with no pool in place - just leaking


This is Cocoa's way of telling you that you need an autorelease pool in place to prevent leaks.

Using autorelease pools is quite simple: NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; sets up a pool. [pool release] cleans it up. They can be nested, so that a function can create one, and then a loop in that function can create its own as well. Nested pools get released automatically when their parent pool is released. This is probably very sloppy, but it appears to work.

Here's some sample code that shows this behavior, as well as usage of NSAutoReleasePool.


#import <Foundation/Foundation.h>

@interface OurObject: NSObject
-(void)dealloc;
@end

@implementation OurObject
-(void)dealloc
{
printf("Dealloc on OurObject\n");
[super dealloc];
}
@end

void createAPoolAndLeak()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
OurObject *oo = [[OurObject alloc] init];

// add to this function's pool...
[oo autorelease];
// ... and forget to release the pool! *Gasp*
}

void createAPoolAndDontLeak()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
OurObject *oo = [[OurObject alloc] init];

// add to this function's pool...
[oo autorelease];
// ... and release the pool!
[pool release];
}

int main()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

printf("Creating a pool and not leaking...\n");
createAPoolAndDontLeak();
printf("Pool cleaned up.\n");
printf("Creating a leaky pool\n");
createAPoolAndLeak();
printf("Leaky pool created.\n");

printf("Releasing parent pool...\n");
[pool release];

printf("Pool is cleaned up...\n");
return 0;
}


Using these pools is disappointingly simple. They really don't require much work at all.

1 comment:

Oliver said...

Thanks - making some clear statements about the NSAutoreleasePool helped me understanding the Objective-C memory management a bit better :)

Categories