Memory Management in the Cocoa Touch Framework
- Memory Management Basics
- Reference Counting
- For the More Curious: More on Memory Management
Understanding memory management in the Cocoa Touch framework is a major roadblock for newcomers. Unlike Objective-C on the Mac, Objective-C on iOS has no garbage collector. Thus, it is your responsibility to clean up after yourself.
Memory Management Basics
This book assumes you are coming from a C background, so the words "pointer," "allocate," and "deallocate" shouldn't scare you. If your memory is a little fuzzy, here's a review.
An iOS device has a limited amount of random access memory. Random access memory (RAM) is much faster to write to and read from than a hard drive, so when an application is executing, all of the memory it consumes is taken from RAM. When an operating system like iOS launches your application, it reserves a heaping pile of the system's unused RAM for your application. Notso-coincidentally, the memory reserved for your application is called the heap. The heap is your application's playground; it can do whatever it wants with it, and it won't affect the rest of the OS or any other application.
When your application creates an instance of a class, it goes to the giant heap of memory it was given and takes a little scoop. As your application runs, you create objects and start using more and more of the heap. Most objects are not permanently necessary, and when an object is no longer needed, the memory it was consuming should be returned to the heap. Then that memory can be reused for an object you create later.
This dynamic use, return, and reuse of memory requires proper management. Two major problems occur when memory is not managed properly:
premature deallocation |
A chunk of memory is returned to the heap before a part of the program is finished using it. |
memory leak |
A chunk of memory is no longer needed by any part of a program, but it is not freed up to be used for something else. |
Managing memory in C
In the C programming language, you explicitly ask the heap for a certain number of bytes. This is called allocation, and it is the first stage of the heap life cycle shown in Figure 3.1. To allocate memory, you use a function like malloc. If you want 100 bytes from the heap, you do something like this:
void function(void) { char *buffer = malloc(100); }
Figure 3.1 Heap allocation life cycle
You then have 100 bytes with which you can perform a task like writing a string to these bytes and then printing that string (which requires reading from those bytes). The location of the first of the 100 bytes is stored in the pointer buffer. You use this pointer to access the 100 bytes (Figure 3.1).
When you don't need those bytes anymore, you give them back to the heap by using the free function. This is called deallocation.
void function(void) { char *buffer = malloc(100); // Do something with buffer free(buffer); }
Calling free returns the 100 bytes (starting at the address stored in buffer) to the heap. If another malloc function is executed, any of these 100 bytes is fair game to be returned. Those bytes could be divvied up into smaller sections, or they could become part of a larger allocation. Because you don't know what will become of those bytes when they are returned to the heap, it isn't safe to access them through the buffer pointer anymore.
Managing memory with objects
Even though at the base level an object is also a certain number of bytes allocated from the heap, you never explicitly call malloc or free with objects.
Every class knows how many bytes of memory it needs to allocate for an instance. When you create an instance of a class by sending it the alloc message, the correct number of bytes is allocated from the heap. Like with malloc, you are returned a pointer to this memory. However, when using Objective-C, we think in terms of objects rather than raw memory. While our pointer still points to a spot in memory, we don't need to know the details of that memory; we just know we have an object.
Of course, once you allocate memory, you need a way to return it. Every object implements the method dealloc. When an object receives this message, it returns its memory to the heap.
So, malloc is replaced with the class method alloc, and the function free is replaced with the instance method dealloc. However, you never explicitly send a dealloc message to an object; an object is responsible for sending dealloc to itself. That begs the question: if an object is in charge of destroying itself, how does it know when it is safe and right to do so? This is where reference counting comes into play.