Track GC Memory Usage Using Instruments

Content

Track GC Memory Usage Using Instruments

Posted in:

When tracking GC memory usage it is essential to be able to examine the heap object graph. That's where Instruments comes in.

Using ObjectGraph

The GC Monitor Instruments template provides a default set of tools used to profile GC based apps. Reading the Instruments documentation is essential, but is no substitute for blind perseverance in this case. There is a lot of detail available and it takes time to figure out just what some of it means.

The ObjectGraph tool provides a snapshot based way of examining a running apps heap object graph. Unfortunately, in Xcode 3.6.2, there is no documentation. My deductions for use are as follows.

Track Pane

The Track Pane shows the used heap allocation in the top trace and the overall allocation in the bottom trace. Drag the playhead to see the numbers.

Snapshots

The ObjectGraph detail view reveals the snapshot nature of this tool. The tool defaults to taking periodic snapshots of the application's running heap object graph.

Block Filters

The Roots Only option can help you identify the graphs root objects. When combined with User Defined Only you can quickly determine which of your applications objects are rooted.

Detail Pane Search Field

Using the Detail Pane bottom search field you can quickly determine if a given class is currently alive in the graph.

Using Snapshots

When ObjectGraph takes a snapshot it places a green marker in the Track Pane. By default the ObjectGraph detail view shows all objects in the graph for all markers. So if the Track Pane contains 5 snap shot markers then the detail view will contain information on all the objects in the graph as detected by all 5 snap shots. This may not be what you require.

To view the object graph for a particular snapshot use the Inspection Range toolbar control to bracket the required snapshot marker. This enables you to detect if a particular object is present in the graph at the time the snapshot was taken.

Roots

Rooted objects are either global variables, stack variables or objects with external references. The ObjectGraph displays all the allocated objects in the application graph. Block Filters can be used to filter the Object Graph Root Listing.

  • Roots Only list only those objects identified as roots.
  • Exclude Non Objects exclude block allocations made for non objects.
  • User-Defined Only list only user defined objects

Often it is useful to determine which object is maintaining a reference to another and thus possibly preventing it from being collected. This can be achieved by selecting Invert References in Reference Options. When selected each block can be expanded to reveal those objects in the graph that reference it.

In the example below I had previousy identified that instances of MGSConfigurationAccessWindowController were not getting collected in all cases. With Invert References selected I can see that two instances of MGSNetRequest are retaining references to the problem object. These look suspicious.

instruments-gc-1.png

Expanding the first MGSNetRequest instance reveals the graph shown below. This can be interpreted as follows.

  1. MGSNetClientManager is rooted and most likely an application singleton.
  2. MGSNetClientManager _selectedNetClient references an instance of MGSNetClient.
  3. MGSNetClient _executingRequests is an array that contains a reference to an MGSNetRequest object.
  4. MGSNetRequest _owner references the initial MGSConfigurationAccessWindowController instance.

Thus we can trace our problem object back to its root. In this case the MGSConfigurationAccessWindowController object was not getting collected because an MGSNetRequest instance was not being correctly removed from the array of executing requests.

instruments-gc-2.png

In many cases application root objects will be statically allocated singletons and the Extended Detail pane will identify those.

Objects currently on the stack at the time the snapshot was taken will also be rooted. These may be reported as multiple stack roots which just indicates that references these objects are present on the heap in multiple locations, probably as a result of their use in function calls.