Channels ▼
RSS

Tools

Debugging Memory in iOS Apps


Software products slated for the iOS market have to be frugal in their use of memory. iOS devices such as the iPhone and iPad have limited physical memory, much less than their flash storage. Using Xcode can help design frugal code and subject source files to static analysis. You can also use its Instruments tool to track down memory problems at runtime. In this article, I discuss some common memory problems and how they can affect a typical iOS app. I show you how to detect these problems with the aforementioned tools and some ways of fixing them.

You will need a working knowledge of ANSI-C, Objective-C, and Xcode. The sample project needs version 3.x (or newer) of the Xcode development suite.

Types of Memory Problems

Most memory problems are one of four types. The first type is the dangling pointer. This is an object or data pointer that still refers to a deallocated memory block. The block may still have valid data, but the data can "disappear" at some point in time. Attempts to access a dangling pointer may lead to a segmentation fault (EXC_BAD_ACCESS or SIGSEGV). A dangling pointer should not be confused with a NULL, which is defined as ((void *) 0).

Consider the snippet in Listing One. Here, class FooProblem has a single property (objcString) and a single action method. The action method, demoDanglingPointer:, initializes objcString to an empty NSString (line 18). Then, in a separate code block, it creates an instance of NSMutableString (line 20). It sends the instance a release message (line 22), but also assigns that same instance to objcString (line 25). Once the code block exits, deallocation occurs and objcString is left holding a dangling pointer.

Listing One

// -- FooProblem.h
@interface FooProblem : NSObject
{ 
	// -- properties:demo
	NSString *objcString;
}

// -- methods:demo:actions
- (IBAction) demoDanglingPointer:(id)aSrc;
@end

// -- FooProblem.m
@implementation FooProblem
- (IBAction) demoDanglingPointer:(id)aSrc
{
	NSString *tBar;
	
	objcString = [NSString string];
	{
		tBar = [[NSMutableString alloc] initWithString:@"foobar"];
		//... do something else
		[tBar release];
	}
	//..do something else
	objcString = tBar;	
}
@end

Now consider now the snippet in Listing Two. This variant of FooProblem declares a C struct named FooLink (lines 1-6). In its demoDanglingPointer: action, it declares the local variable tTest and assigns the latter the output from method danglingPosix() (line 26). The danglingPosix() method creates a local instance of FooLink (tBar) inside a code block (lines 38-41). It assigns values to the struct fields and sets the local tFoo to tBar (line 42). But just before the code block exits, danglingPosix() disposes of tBar with a call to free() (line 44) and returns the pointer held by tFoo (line 48). The result — local tTest now has a dangling pointer.

Listing Two

typedef struct Foo
{
	char *fFoo;
	unsigned int fBar;
	struct Foo *fNext;
} FooLink;

// -- FooProblem.h
@interface FooProblem : NSObject
{ 
	// -- properties
	//...
}

// -- methods:demo:actions
- (IBAction) demoDanglingPointer:(id)aSrc;
- (FooLink *)danglingPOSIX;
@end

// -- FooProblem.m
@implementation FooProblem
- (IBAction) demoDanglingPointer:(id)aSrc
{	
	FooLink *tTest;
	
	tTest = [self danglingPOSIX];
	// ...do something else
}

- (FooLink *)danglingPOSIX
{
	FooLink *tFoo;
	
	// initialise the output result
	tFoo = nil;
	
	{
		FooLink *tBar;
		tBar = malloc(sizeof(FooLink));
		tBar->fFoo = "foobar";
		tBar->fBar = 1234;
		tFoo = tBar;
		//... do something else
		free(tBar);
	}
	
	// return the string result
	return (tFoo);
}
@end

The next type of memory problem is the double free. This occurs when a code routine tries to dispose of an object or structure that has already been disposed of. Disposal need not happen in succession, so long as it affects the same pointer. A double free also leads to a segmentation fault, followed by a crash.

Listing Three is a classic example of a double free. The action method demoDoubleFree: creates an instance of FooLink and populates its fields (lines 3-5). It sends the instance to the method doubleFreePOSIX:, which updates the two fields (lines 14-15). But then doubleFreePOSIX: disposes of the FooLink instance with a call to free() (line 18). When it returns control to demoDoubleFree:, demoDoubleFree: also disposes of the same FooLink structure using free() (line 8).

Listing Three

- (IBAction) demoDoubleFree:(id)aSrc
{		
	tFoo = malloc(sizeof(FooLink));
	tFoo->fFoo = "Foobar";
	tFoo->fBar = 12345;
	
	[self doubleFreePOSIX:tFoo];
	free(tFoo);
}

- (void)doubleFreePOSIX:(FooLink *)aFoo
{
	//...do something else
	aFoo->fFoo = "BarFoo";
	aFoo->fBar = aFoo->fBar + 123;
	
	//... do something else
	free(aFoo);
}

Listing Four shows another double free example. The action method demoDoubleFree: creates and adds an NSNumber instance to the mutable array property objcArray (lines 23-24). Then it invokes the method doubleFreeObjC. This method parses the array property and uses its entries to create an NSString object (line 39-40). Later, it sends a release message to each entry (line 44). If the entry is the NSNumber object, a double free error occurs. This is because the NSNumber object was marked for autorelease. An explicit release interferes with the autorelease pool's attempt to dispose of the object.

Listing Four

// -- FooProblem.h
@interface FooProblem : NSObject
{ 
	// -- properties
	NSMutableArray *objcArray;
}

// -- methods:demo:actions
- (IBAction) demoDoubleFree:(id)aSrc;

// -- methods:demo:utilities
- (void)doubleFreeObjC;
@end

// -- FooProblem.m
@implementation FooProblem
// ...truncated for length

- (IBAction) demoDoubleFree:(id)aSrc
{		
	NSNumber *tNum;
	
	tNum = [NSNumber numberWithLong:rand()];
	[objcArray addObject:tNum];
	
	//...do something else
	
	[self doubleFreeObjC];
}

- (void)doubleFreeObjC
{
	NSString *tText;
	id tObj;
	
	tText = [NSString string];
	for (tObj in objcArray)
	{
		tText = [tText 
			stringByAppendingFormat:@"/@", tObj];
		
		//...do something else
		
		[tObj release];
	}
}
@end

A memory leak is another typical memory problem. It occurs where a routine fails to dispose of its objects or structures. The failure may be due to an error or exception, or it may be due to poor code design. A continuous memory leak can lead to a low-memory condition. At best, it could cause iOS to terminate the offending app. At worst, it could force users to perform a hard reset.

Listing Five is one example of a memory leak. This variant of FooProblem creates an empty NSMutableArray instance and assigns it to the property objcArray (lines 17-18). Its dealloc method, however, does not send a release message to objcArray. The result is, of course, a memory leak, even if the array object remains empty.

Listing Five

// -- FooProblem.h
@interface FooProblem : NSObject
{ 
	// -- properties
	NSMutableArray *objcArray;
}
@end


// -- FooProblem.m
@implementation FooProblem
- (id)init
{
	if (self = [super init])
	{
		// prepare the following properties
		objcArray = [[NSMutableArray alloc] 
			initWithCapacity:1];
		
		return (self);
	}
	else
		// the parent has failed to initialise
		return (nil);
}

//...other methods go here

- (void)dealloc 
{
	//...do something else
	
	// pass the message to the parent
    [super dealloc];
}
@end


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