Channels ▼
RSS

Design

Debugging Memory in iOS Apps


A session can have one or more modules, all targeting the same process. The Instruments tool comes with at least a dozen modules for monitoring an iOS app process. It also has facilities for creating a custom module. But there are just two modules that are suited to memory debugging.

First is the Allocations module (Figure 4). This module records every type of object or structure created and disposed of by the app process. It keeps track of each object's retention and reference count. It can even recast deallocated objects as zombies (for flagging any attempts to use a deallocated object).


Figure 4.

The second is the Leaks module (Figure 5). This module looks for objects or structures that are potential leaks. It displays each leak as a bright-colored spike overlaid against a running total of leaks. It can be used alone, but it is often used in conjunction with the Allocations module.


Figure 5.

Debugging with Instruments

To prepare the iOS app for a debug session, first make surethat the app builds without error and installs into the IOS simulator. Make sure it has displayed its main window and it can respond to user clicks. If the app crashed or froze at launch time, the memory problem is likely in its init code.

Next, comment out or remove all calls to NSLog(). NSLog() delivers its log messages as NSString objects. These objects can cause confusion, especially when the problem is due to an NSString. Isolating NSLog() calls helps reduce the number of string objects to be monitored.

Finally, use only the version of Instruments that came bundled with the active Xcode IDE. For Xcode 3.2.6, it is Instruments 2.7. For Xcode 4.2, it is Instruments 4.2. A different version of Instruments may not work properly with a given IDE session. At best, Instruments will crash when it tries to acquire process data.

Figure 6 shows the session setup used in this article. On it are the Allocations and Leaks module described earlier. The Allocations module is prepped to track all objects and structures, record reference counts, and employ zombies. The Leaks module is prepped to look for leaks at one-second intervals. The setup also includes the Sampler module. This module keeps track of processes on the iOS simulator. With it, you can verify if a memory problem is caused by the target process and not some other errant process.


Figure 6.

To connect to the target app, click on the Target pop-up button and choose the process name from the submenu Attach to Process. In our sample setup, the target app is FooDebug with a process ID of 24912. To start a trace, choose Mini Instruments from the Instruments' View menu. This collapses the session window into a basic translucent record window (Figure 7). Click the record button on that window to start acquiring process data, and run the desired feature or task on the app. Click the record button again to end acquisition, and the close button to view the results. If your display is large enough, you could dispense with the Mini Instruments mode and have both session window and iOS simulator side by side.


Figure 7.

Figure 8 shows how an ObjC memory leak appears in the session window.


Figure 8.

The routine in question is the action method demoMemoryLeak: (Listing Nine) executed twice.

Listing Nine

- (IBAction) demoMemoryLeak:(id)aSrc
{
	NSMutableString *tLeak;
	NSNumber *tNum;
	
	// prepare a new string object
	tNum = [NSNumber numberWithLong:rand()];
	tLeak = [[NSString alloc] 
		initWithFormat:@"%d", tNum];
	
	// update the following private property
	objcString = tLeak;
}

Each memory leak appears as a red spike in the Track pane next to the Leaks module. Selecting a spike using an Option-drag reveals the leak as an NSCFString object. Clicking the right-arrow icon next to the object's pointer address (0x4e2a8b0) starts a drill-down. It shows that the leak was caused by the instance method initWithString:. One way to correct this leak is to use the factory method stringWithString: to create the string object. Another way is to replace line 12 in Listing Nine with these statements:

  [objcString release];
  objcString = tLeak;

Figure 9 shows another memory leak. This one was caused by the demoMemoryLeak: method described back in Listing Six. Here, too, each red spike marks each leak that appeared. Selecting a spike reveals the leak: a malloc'd 16-byte data structure with a pointer address of 0x4b56020. It also reveals the name of the action method. A drill-down on the structure supplies more details about the leak.


Figure 9.

To fix this leak, try inserting this statement before line 16 of Listing Six:

  free(posxLeak);

Figure 10 shows the session tracking a double free problem. The target routine in this one is the demoDoubleFree: action method described in Listing Four. Three spikes show the allocations made just before the app crashes with an EXC_BAD_ACCESS. Selecting these spikes bring up the single CFNumber object (0x4d11970) that demoDoubleFree: created and added to objcArray. A drill-down then reveals the object's retention history.


Figure 10.

CFNumber is the Core Foundation analogue of NSNumber. Upon its creation, the object starts with the expected retain count of 1. It is also marked for autorelease due to the use of a factory method. When the object is added to the array, its retention count goes up by 1. The doubleFreeObjC: method extracts the object from objcArray, and retain count goes down by 1.

But then doubleFreeObjC: sends the CFNumber object a release message. When doubleFreeObjC: exits, the autorelease pool reacts by sending its own release message to the same object. The retain count falls below zero and EXC_BAD_ACCESS occurs. One way to fix this problem is to remove the explicit release message (line 44) from doubleFreeObjC:.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video