AddThis Social Bookmark Button

Listen Print Discuss

Knowing When to Let Go: Better Living Through Memory Management

by Rob Rix
06/10/2003

To get a reasonable picture of why memory management is such an important topic, you should first have a reasonable picture of what memory management actually is. In light of that, be prepared, because we're going to cover a fair amount of ground.

By the time we're finished you should have a good understanding of memory management not only as it pertains to Cocoa but also in general, which should be helpful in a variety of circumstances as memory management is fairly ubiquitous.

If You Love Something, Let it Go

The basic idea of memory management is, simplifying only a little, to keep objects (whether they be Objective-C objects or the more general "memory objects" or chunks of memory) around exactly as long as they're needed. Think about writing a program and how long each object will need to exist. In a perhaps typical document-based program, it might break down like this:

These categories don't necessarily fit all kinds programs one might write, but they give a pretty good idea of how lifetimes break down. Recall that memory management means to keep objects around exactly as long as they're needed. So now let's look at a few strategies for doing that or as close to that as we can get.

Malloc/Free

Perhaps the most basic form of memory management that's still reasonably useful is malloc/free. These are two functions in the standard C library which allocate a chunk of memory and delete it (freeing it for use elsewhere), respectively.

The problem with malloc/free is pretty simple: what do you do when an object needs to be used by two chunks of code that can be run at different times? There is a very real and very dangerous possibility that one chunk of code will free the object before the other is done using it, and that it could be written over with data by a totally unconnected piece of code.

Retain/Release

Clearly objects need some sort of indicator to let them know when everybody's done using them. One solution is the retain/release mechanism, something that will be of interest to anyone writing software with Objective-C/Cocoa since it's the mechanism Cocoa uses.

With retain/release, each object has a retain count, an unsigned integer which indicates how many chunks of code need it to exist. Use of this mechanism breaks down as follows:

Now that we've got them out in the abstract, let's look at some examples of how these methods are actually used.

-(void)exampleOfRetaining
{
	id object = [[SomeClass alloc] init];
	NSLog(@"the retain count is %d", [object retainCount]);
	
	[object retain];
	NSLog(@"now it's %d", [object retainCount]);
	
	[object release];
	NSLog(@"and now it's %d", [object retainCount]);
	
	[object release];
}

Related Reading

Cocoa in a Nutshell
A Desktop Quick Reference
By Michael Beam, James Duncan Davidson

Table of Contents
Index
Sample Chapter

Read Online--Safari Search this book on Safari:
 

Code Fragments only

If we compile and run this code, we'll see that the object's retain count is always greater than zero. The first NSLog will tell us it's 1, the second that it's 2, and the third that it's 1 again. Why?

The first operation that touches object's retain count is id object = [[SomeClass alloc] init]. Looking at our list of retain/release methods again, we see that -alloc sets the retain count to its initial state of 1. Since we don't change the retain count after that, the first NSLog shows a retain count of 1. So far, so good.

Next we see [object retain]. Checking against our list we see that -retain increases the retain count by 1. This matches nicely with the second log, showing the retain count to be 2; it's as simple as 1 + 1.

After that, we see [object release]. Once again looking at our list, we see that half the responsibility of -release is decreasing the retain count by 1... and as we all know, 2 - 1 = 1, which explains the last NSLog output.

But what about that last [object release] right at the end? This line shows off the other responsibility of -release: after it decreases the retain count by 1, it notices that it's now 0. And since an object with a retain count of 0 doesn't need to exist any longer, it calls -dealloc, which releases the object's instance variables and ultimately frees the memory the object was occupying. Our object no longer exists, which is just as it should be.

This is perfect for situations where we don't have to return an object, but what about methods that create objects? We've already seen a few guidelines: +alloc, -copy, and -mutableCopy must all create a new object with a retain count of 1. But what about all those lovely "factory"-type methods like NSString's +stringWithFormat:?


Pages: 1, 2

Next Pagearrow