This post is targeted at people who want to know how Objective-C’s memory management features work, particularly the autorelease feature…

Memory management

Objective-C is a great language but it does have its limitations, one of which is the fact it still uses reference counting for memory management, rather than garbage collecting. This can be the source of many issues to the un-initiated, resulting in application crashes and memory leaks. I’m not going to rehash the details found on the Apple developer website, as they provide some very useful guidance on memory management.

I do want to cover some of the lesser-known things about using autorelease for memory management. At first glance it seems like using autorelease is the way to go, as it removes the need for the developer to worry about releasing the object themeselves. There are a few hidden issues with using autorelease. Don’t get me wrong, autorelease has its place and is useful in many circumstances, but it needs to be used wisely.

One of the places you should not use autorelease is in tight loops with many iterations. Autorelease objects are automatically released but only at the end of the system run loop. If you have a tight loop using autorelease objects these will build up in memory whilst the loop is executing and wont be released until the tight loop finishes and the system run-loop completes. For example the following code sample isn’t the best, due to its use of autorelease:

for (int j=0; j < 1000; j++) {

NSString *myString = [[NSString alloc] initWithFormat:@”output %@”,data] autorelease];

//rest of loop code

}

You might choose to add your own autorelease pool within the loop to better manage the release of objects built up during the loop, but this then adds overhead to the loop and can cause performance degradation. So when creating objects within a loop, it is almost always best to manage the memory yourself, to avoid the autorelease pool, and make better use of the limited memory a device has available. Within a loop it is usually easy to allocate and release your own objects, as the objects are generally only alive for each iteration of the loop. Where this gets murky is if you make use of the Class helper methods for creating objects, like:

[NSString stringWithFormat:@”output %@”,data];

These style of constructors make use of the autorelease feature under the hood to manage memory. So if you make use of lots of these functions within a tight loop you can end up using a lot of memory and causing memory spikes, before the loop completed and the autorelease pool is drained at the end of the system run loop. So in these situations you should consider moving to manually allocating and releasing the objects yourself. Yes, this results in slightly more code, but it also results in more even memory management. For instance you should modify your code to read:

for (int j=0; j < 1000; j++) {

NSString *myString = [NSString alloc] initWithFormat:@”output %@”, data];

//rest of loop code

[myString release];

}

Another area where large amounts of memory can be temporarily leaked is in using [UIImage imageNamed:] style methods, if used within a tight loop. UIImage can consume a large amount of memory, for high-resolution images. So this is another target for manual memory management if possible within tight loops.

Your application has a global autorelease pool in place (look to main.m to see how this is created), but when you spawn a new thread, it does not have an associated autorelease pool.  If you use an autoreleased object within your thread, you will see warnings like this appearing all over your console:

_NSAutoreleaseNoPool(): Object 0xf20a80 of class NSCFNumber autoreleased with no pool in place – just leaking

To prevent these objects from being leaked, you’ll need to create a new autorelease pool at the start of your thread:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

and drain it at the end:

[pool drain];

General memory troubleshooting advice

When dealing with memory management issue always make sure that you utilise the tools provided within XCode. Make use of the static analyser, to identify memory leaks. Also make sure to run the Performance tools to measure the memory utilisation on an actual device, whilst it is running. This will generally identify any leaked memory or memory that is held for too long.

Another useful thing to implement is the following method in the AppDelegate:

(void)applicationDidReceiveMemoryWarning:(UIApplication *)application

This allows your application to act as a good citizen and free up memory when the device starts running low on memory. You should remove any cached data, that can be easily reloaded when you application needs it at a later point. Now with iOS4.0 and multitasking your application is not normally exited, so continues to use memory even when running in the background.

Tagged with:
 

2 Responses to Understanding Objective-C autorelease memory management

  1. Lada says:

    Thanks for the article. I started self-learning Objective C more the year ago and I never understood this memory management. I made a couple of apps without taking care of releasing, it somehow worked. But now I have difficulties with [UIImage imageNamed:] as you mention. Is there a better way to show a jpeg from app´s bundle than this one? You say this method contains autorelease inside. It means that if I load this UIImage into UIImageView and then release that view then the image is released automatically, right? When I add it as subview to a view which is permanently shown on the screen then the autorelease cue is damaged? It must be because the image survives many system loops then, apparently is not autoreleased. But then when I removeFromSuperview the view, which should mean the superview releases my view with the image, then is it released or not? I’m completely lost :-(

    • Brendon says:

      When you add a UIImage to a UIImageView, the UIImageView increases the retain count on the UIImage object, stoping it from being released, until you release the containing UIImageView. So if you add this view onto the screen, it will be retained until the view is removed via removeFromSuperview, at which point the retain count will be decreased and the UIImage can finally be released.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Talk to us!

We'd love to chat about ways to make innovation happen faster in your organisation.