Home / iPhone Tips and Tutorials

Managed Memory Model Design Pattern

As powerful as it is, the iPhone is limited in resources, and the most critical of these resources is memory.

To truly understand how to manage memory correctly in your application, you need to understand how the iOS memory works.

Understanding memory management

Whenever you (or a framework object) create an object using Objective-C, you allocate memory for the object. Although the iPhone OS and the Mac both use what's known as virtual memory, unlike the Mac, virtual memory in the iPhone is limited to the actual amount of physical memory. So when it begins to run low on memory, the iPhone OS frees memory pages that contain read-only content (such as code); this way, all it has to do is load the "originals" back into memory when they're needed. In contrast to what the Mac does, the iPhone doesn't temporarily store "changeable" memory (such as object data) to the disk to free space and then read the data back later when it's needed. This state of affairs limits the amount of available memory.

So as you can see, when one object is done using memory, it is critical that the memory be released for use by other objects.

If memory continues to be limited, the system may also send notifications to the running application, asking it to free additional memory. This is one of the critical events that all applications must respond to, and I explain this process in the section "Observing Low-Memory Warnings," later in this article.

In Objective-C, memory is managed on the iPhone apps by reference counting - keeping the system up to date on whether an object is currently being used.

Using reference counting

In many ways, Objective-C is like the coolest guy in your school who now makes a seven-figure income surfing, bungee jumping, and skateboarding during the summers and then snowboarding around the world in the winter. In other ways, though, Objective-C is like the nerd in your class who grew up to be an accountant and reads the Financial Times for fun. Memory management falls into this category.

In fact, memory management is simply an exercise in counting. To manage its memory, Objective-C (actually the iOS memory manager) uses a technique known as reference counting. Every object has its own reference count, or retain count.

As long as the retain count is greater than zero, the memory manager assumes that someone cares about that object and leaves it alone.

When an object's retain count goes to zero, the memory manager knows that no one needs it anymore and sends the object a dealloc message, and after that, its memory is returned to the system to be reused.

That process sounds pretty straightforward, but how does the retain count get incremented and decremented?

Until Xcode 4.2 and iOS 5.0, you had to manage the retain count in your application. When an object is created via alloc or new or through a copy or mutableCopy message, the object's retain count is set to 1. When your application uses one of those methods, ownership is transferred to the "caller" - that is, the object has been retained for the caller and it becomes a nonexclusive owner of the object. Ownership here means that the object will be there to use until it's explicitly released by sending it a release message when it is longer needed (although if there are other active owners, it wouldn't be de-allocated until all of them have released it).

Before Xcode 4.2 and iOS 5.0, if you didn't create an object by one of those methods but you wanted to become an owner, thereby making sure that the object stayed around for you to use until you were done with it, it was up to you to send a retain message to increase the retain count, and when you were done, to send a release message. This was because the creator of the object (which caused the retain count to be set to 1) may have auto released it - sent an object a "deferred" release message. This is useful in situations in which you want to relinquish ownership of an object but avoid the possibility of its being deallocated immediately (such as when you return an object from a method).

In either instance, you were maintaining a pointer to the object so that it could be used.

Although this approach was simple in theory, it was a real headache for programmers. The vast majority of system crashes occurred because apps ran out of memory and were shut down by the system.

In some of these cases, the application didn't respond to the memory warning methods and manage the low-memory warnings, explain in "Observing Low-Memory Warnings," later in this article.

Most of the time, however, even if the application responded to the lowmemory warnings. It was limited to what it could do because the memory was leaked. Memory was actually available because some objects were not being used, but those objects' memory had not been released back to the system. But there were no longer pointers to these objects (for a variety of reasons), so they couldn't be released and then deallocated and the memory reused.

There are ways to manage memory automatically. One is garbage collection, which scans through memory and releases objects that have no pointers to them. Garbage collection for Objective-C is available on the Mac (and for many other languages on other platforms), but garbage collection has a few problems. Garbage collection can start up and "pause" your applications at the most inopportune time, and it affects performance and the user experience because you have no control, or any idea, when it will occur.

Having to do all this memory management in your application has all changed with the latest version of the Objective-C compiler with the introduction of automatic Reference Counting (ARC). ARC does for you in the compiler what you used to have to do on your own. It handles all those releases, autoreleases, and retains for you.

[Previous] [Contents] [Next]