Locating Memory Issues in Your App

Managing the memory that your app uses is one of the most important aspects of creating an app. From the smallest iOS device to the largest OS X computer, memory is a finite resource. This chapter describes how to identify common memory issues, from memory leaks to zombies.

Examining Memory Usage with the Activity Monitor Trace Template

The Activity Monitor trace template monitors overall system activity and statistics, including CPU, memory, disk, and network. It also monitors all existing processes and can be used to attach new instruments to specific processes, monitor parent-child process hierarchies, and to quit running processes. It consists of the Activity Monitor instrument only. You’ll see later that the Activity Monitor is also used to monitor network activity on iOS devices.

The Activity Monitor instrument provides you with four convenient charts for a quick, visual representation of the collected information. The two charts that describe memory usage are:

Figure 7-1 shows the top five users of memory on the system.

Figure 7-1  Activity Monitor instrument with charts

The following configuration options provide memory-specific information through the Activity Monitor. For statistic definitions and complete configuration options, see “Activity Monitor Instrument” in Instruments User Reference.

Recovering Memory You Have Abandoned

The Allocations trace template measures heap memory usage by tracking allocations, including specific object allocations by class. It also records virtual memory statistics by region. It consists of the Allocations and the VM Tracker instruments.

Avoid abandoned memory by ensuring that the heap does not continue to grow when the same set of operations are continuously repeated. For example, opening a window then immediately closing it, or setting a preference then immediately unsetting it are operations that conceptually return the app to a previous and stable memory state. Cycling through such operations many times should not result in unbounded heap growth. To ensure that none of your code abandons memory, repeat user scenarios and use the Mark Generations feature after each iteration. After the first few iterations (where caches may be warmed), the persistent memory of these iterations should fall to zero. If persistent memory is still accumulating, select the focus arrow to see a call tree of the memory. There you can identify the code paths responsible for abandoning the memory. Ensure that your scenarios exercise all your code that allocates memory.

bullet
To find memory abandoned by your app
  1. Open the Allocations template.

  2. Choose your app from the Choose Target pop-up menu.

  3. Click the Record button.

  4. Repetitively perform an action in your app that starts from, and finishes in, the same state.

  5. After each iteration of the repeated action, click the Mark Generations button to take a snapshot of the heap.

  6. Repeat steps 4 and 5 until you see whether the heap is growing without limit, and then click the Stop button.

  7. Analyze objects captured by the heapshots to locate abandoned memory.

    ../Art/Abandoned_memory_example.png

If the heap continues to grow after the first few iterations of the cycle, you know your app is abandoning memory. Find a heapshot that seems representative of the repeated heap growth. Click the focus button to the right of the heapshot name to display objects created during that time range that are still living after the app has executed.

After you stop the trace, you can still take snapshots by dragging the inspection head in the trace window timeline to where you want the snapshot, and clicking Mark Generations. After stopping the trace, take one last snapshot at the end of the trace. At that point, the number of persistent objects should be zero.

Finding Leaks in Your App

The Leaks trace template measures general memory usage, checks for leaked memory, and provides statistics on object allocations by class as well as memory address histories for all active allocations and leaked blocks. It consists of the Allocations and Leaks instruments.

Use the Leaks instrument to find objects in your app that are no longer referenced and reachable. The Leaks instrument reports these blocks of memory. Most of these leaks are objects and are reported with a class name. The others are reported as Malloc-size.

bullet
To locate leaking memory
  1. Open the Leaks instrument.

  2. Choose your app from the Choose Target pop-up menu.

  3. Click the Record button.

  4. Exercise your app to execute code, and click the Stop button when leaks are displayed.

  5. Click any leaked object that is identified in the Detail pane.

  6. Within the Extended Detail pane, double-click an instruction from your code.

  7. Click the Xcode icon in the Detail pane to open that code in Xcode.

    ../Art/Leaks_found.png

After opening Xcode to see the piece of code that is creating the leak, the cause of the leak may still be unclear. The Leaks instrument allows you to see the cycle that is creating the leak in the Cycles & Roots option in the Detail pane. It provides a graph of the reference cycle that is causing the leak.

bullet
To see the cycle graph of a leak
  1. Select the Leaks instrument.

  2. Select Cycles & Roots in the Detail pane.

  3. Select the leak whose graph you want to see.

    ../Art/Leaks_cycle_graph.png

Eradicating Zombies with the Zombies Trace Template

The Zombies trace template measures general memory usage while focusing on the detection of overreleased, “zombie” objects. It uses the Allocations instrument to display statistics on object allocations by class as well as memory address histories for all active allocations. Note that, because the Zombies trace template uses a “debug” mode, many other values displayed by the Allocations instrument will not be meaningful.

The Zombies trace template sets the variable NSZombieEnabled to true which directs the compiler to substitute an object of type NSZombie for objects that are released to a reference count of zero. Then, when a zombie is messaged, the app crashes, recording stops, and a Zombie Messaged dialog appears. Clicking the focus button to the right of the message in the Zombie Detected dialog displays the complete memory history of the overreleased object. Note that this memory history is the only part of the Allocations Instrument that is meaningful when using the Zombies trace template.

bullet
To find zombies in your code
  1. Open the Zombies template.

  2. Choose your app from the Choose Target pop-up menu.

  3. Click the Record button and exercise your app.

  4. When a Zombie Messaged dialog appears, click the focus button to the right of the message text in the dialog.

  5. Open the Extended Detail pane and double-click the zombie event type in the object history table.

  6. In the stack trace that appears, double-click Responsible Caller to display the responsible code.

    ../Art/Zombies_found.png