Heapshot Analysis

Heapshot Analysis is an excellent Instruments tool that I use quite frequently in my work. It is great at tracking down abandoned memory, which will sometimes not get reported as a leak by the leaks tool but is still taking up memory.  It can also track down leaking memory.

To demonstrate how to use Heapshot Analysis in Instruments, I have created a very simple project consisting of two UIViewControllers: a main UIViewController containing a button which pushes to another UIViewController containing a label.

 

The label on the second view controller is setup in with the following code snippet. 

- (void)viewDidLoad
{
[super viewDidLoad];

self.label.text = [[NSString alloc] initWithUTF8String:"A string"];
}

This is obviously wrong and will leak an NSString when the View Controller is destroyed. This is because the retain count on this string is 2. Lets see how we could find this using Heapshot Analysis.  

First, open up Instruments using profile instead of run in Xcode and select the Allocations instrument.

Screen Shot 2013-04-26 at 3.06.54 PM.png

Once the tool opens and the app starts up on the left side click Mark Heap.

Screen Shot 2013-04-26 at 3.07.17 PM.png

Heapshot analysis works by marking the heap at the same point in the app repeatedly; by doing this the tool can report objects that are still alive. Theoretically, in a well designed app doing some process and returning to the same point in the app should return the memory footprint to the same point. If you store results or load caches there will obviously be a difference, but that is still ok, you just need to know not to worry about these objects in your analysis.

In our app we will click on the button to push the second view controller and then tap the back navigation item to go back. At this point we will mark the heap and repeat the process. I repeated this 5 times. This is how Instruments showed the results at the end of it. 

Screen Shot 2013-04-26 at 3.07.45 PM.png

It is ok that Baseline and Heapshot 1 are not zero bytes, as generally this is the result of loading caches in the background. However, Heapshot 2 should drop to zero. Obviously something is not quite right. Lets open up the 2nd Heapshot and see what is hanging around.

Screen Shot 2013-04-26 at 3.08.16 PM.png

We can see that we have a CFString hanging around. Expanding the arrow next to it shows a memory address which we can click on. On the right hand side of Instruments there will now be a view showing how this object was created. We can even double click on the section from our own code to see the line.

Screen Shot 2013-04-26 at 3.08.27 PM.png

There we go, Instruments has found the offending line in our code. By fixing up this line and repeating our analysis, we can see the middle heap shots dropping to zero bytes.

 

Screen Shot 2013-04-26 at 3.23.55 PM.png

Obviously this was a simple case that would be picked up by both the Leaks tool and the Static Analyser; however, it is not always this simple. This tool is often very good at finding retain cycles and more complicated abandoned memory situations, and is a vital tool in any iOS/OSX developers toolbelt.