About Memory Analysis
Whenever your app creates objects, memory is allocated for them. Traditionally, it has been the app’s job to track these objects and release them when they are no longer needed so the memory can be reallocated for other objects. Automatic Reference Counting (ARC) is a feature that makes things easier by putting the system in charge of memory management. With ARC enabled, the system handles monitoring object allocations and releasing them when appropriate, leaving very little for your app to do. Regardless of how memory is managed, though, even the best app designs can encounter occasional memory issues that are difficult to isolate.
Instruments can help by painting a picture of how your app uses memory, making it easier to identify potential problem areas. It can even auto detect certain types of memory problems and flag them for you for analysis. Use instruments to watch for and track the following:
Overall Memory Use. Monitor at a high level how your app uses memory and compare it to the memory usage of other active processes on the system. Look for areas of large or unexpected memory growth. See Monitor Memory Usage.
Leaked Memory. This is memory that was allocated at some point, but was never released and is no longer referenced by your app. Since there are no references to it, there’s now no way to release it and the memory can’t be used again. For example, suppose you’ve written an app that creates rectangle objects in a drawing, but never releases the objects when the drawing is closed. In this case, your app would leak more and more memory whenever a drawing containing rectangles is closed. To fix the leak, you need to figure out which object isn’t being released, and then update your app to release it at the appropriate time. See Find Memory Leaks.
Abandoned Memory. This is memory that your app has allocated for some reason, but it’s not needed and won’t be referenced. For example, suppose your app adds images to a cache after they’ve already been cached—using double the memory for the same images. Or, maybe your app maintains an array of objects in case you need to access them later, but you never actually do. Unlike leaked memory, abandoned memory like this is still referenced somewhere in your app. It just serves no purpose. Since it’s still technically valid, it’s more difficult for Instruments to identify and requires more detective work on your part to find. See Find Abandoned Memory.
Zombies. This is memory that has been released and is no longer needed, but your code still references it somewhere. For example, suppose your app contains an image cache. Once the cache has been cleared, your app shouldn’t attempt to refer to the images that it previously contained. Calls to these nonexistent images are considered zombies—references to objects that are no longer living. See Find Zombies.
Because memory problems can be difficult to find, it’s helpful to take periodic snapshots of your app at various stages in order to look for unexpected or unrestrained memory growth. You can compare snapshots to determine how objects are being allocated and destroyed, and how memory is used over time.
It’s also important to test your app by continuously performing a set of repeatable user actions that cause your app to enter a new state and return to its original state when done. This type of research is known as generational analysis. Each time your app enters its new state, a “generation” of objects is created. In most cases, you should expect these objects to be released when your app returns to its original state. For example, if your app opens a window, then any window objects should be deallocated when the window is closed. If they aren’t, then you may have a memory problem. When performing generational analysis, initial generations may exhibit larger than expected memory use due to caching and other initialization processes. Therefore, repeat user actions multiple times in order to gain a truer sense of your app’s behavior.