Instruments Tutorial for iOS: How To Debug Memory Leaks
An Xcode and Instruments Tutorial that shows you how you can debug memory leaks in your iPhone apps. By Ray Wenderlich.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Instruments Tutorial for iOS: How To Debug Memory Leaks
10 mins
Update 4/12/13: These days, you should probably be using Apple’s new Automatic Reference Counting (ARC) technology instead of doing manual memory management. For more details on ARC, check out our ARC tutorial. We also have an updated Instruments tutorial you might want to check out.
This is the second article in a three-part series on working with memory in Objective-C on the iPhone. In the first part of the series, we covered how to manage memory in Objective-C by using instance variables and reference counting.
No matter how well you understand memory management in Objective-C, from time to time you’re bound to make mistakes. But often there’s way too much code to search line-by-line for problems (unless you want your hair to turn gray!)
Luckily, Apple has provided some great ways to help you find memory-related problems in your applications. Sometimes these tools scare new developers, but they’re actually pretty awesome and easy to use!
That’s what this Instruments tutorial is all about. You’ll get hands hands-on experience using XCode and Instruments to debug and detect memory related problems.
This Instruments tutorial assumes you are familiar with memory management in Objective-C. If you are still shaky on the subject, you may wish to read the memory management tutorial first.
Getting Started
Our goal in this Instruments tutorial is to check for and resolve any memory leaks in an example app that illustrates common memory-related mistakes. So to get started, download a leaky app that I’ve put together for this Instruments tutorial.
Open up the app and run it in XCode. You’ll see a list of sushi in a table view. Try selecting several rows, and then – BOOM! You get the dreaded EXC_BAD_ACCESS error, and the debugger is no help:
This can be very frustrating to many beginning developers, as it’s not clear where the problem is. Here’s the advice I generally give to developers when you hit an EXC_BAD_ACCESS error:
- Set the NSZombieEnabled argument in your executable options, which sometimes helps narrow down the cause
- Run with Apple Instruments such as Leaks to look for memory issues
- Set a breakpoint in your code and step through until you narrow down where it’s crashing
- Tried and true “comment out code till it works” then backtrack from there :]
So let’s try this out for ourselves by trying option #1 – turning on NSZombieEnabled.
Zombie Invasion!
Unfortunately, the NSZombieEnabled option has nothing to do with the zombie apocalypse, so you can put away your boomsticks and chainsaws :]
NSZombieEnabled is a flag that you can enable that will provide a warning when you try to access an object that has been deallocated. And since accessing deallocated memory is one of the most common reasons for crashing, this is a good thing to try first.
To set this up, expand the Executables group in your sidebar in XCode, and double click the PropMemFun executable. Select the Arguments tab, go to the “Variables to be set in the environment” section, and click the Plus button. Set the name of the variable to NSZombieEnabled, and set the value to YES, as follows:
Now run the app, and click on a few rows again until it crashes. Go to your console log, and you’ll see the following message:
2011-02-03 12:07:44.778 PropMemFun[27224:207] *** -[CFString respondsToSelector:]: message sent to deallocated instance ...
The program will also halt on the exact line where it’s crashing now. You can go up the backtrace to find the exact line where it’s crashing by selecting the first area in the backtrace that is your code – in this case tableView:didSelectRowAtIndexPath.
Aha! Now you know that in this line, a message is being sent to a deallocated string. This line uses two strings: _lastSushiSelected, and sushiString.
Well sushiString looks OK, because it’s initialized with stringWithFormat (which returns an autorelease variable), so it should be safe to use until the next run loop. But what about _lastSushiSelected?
_lastSushiSelected was set the last time this method was run to sushiString. But sushiString is an autorelease variable, so at some point it will be released, and the memory will be deallocated. But then _lastSushiSelected would still be pointing to deallocated memory! Which explains the problem – sending a message to deallocated memory causes a crash.
So to solve this, we just need to retain _lastSushiSelected so that the memory doesn’t go away. So replace the last line with the following:
_lastSushiSelected = [sushiString retain];
Compile and run your code, and now you should be able to run without crashing!
Build, Analyze, and Recognize
Ok, so we have an app that isn’t crashing – a good first step. But next, we need to start making sure that it isn’t leaking any memory.
There’s an easy way to perform an initial first-glance check on your app to see if it has any memory leaks or other problems – use the built-in Build and Analyze function.
This will make XCode run through your code and look for any mistakes it can automatically detect, and warn you about any potential problems. It doesn’t catch everything, but when it does catch things it’s a really quick and easy way to find out about the problems.
Give it a shot by selecting Build\Build and Analyze. You should see that it detected a memory leak, as you can see below:
The message says that there’s a potential leak related to the “alertView”. If you look at this line, you’ll see that the UIAlertView was created with a alloc/init (which returns an object with a reference count of 1), but never released! There are several ways to fix this, but one way is to add the following after [alertView show]:
[alertView release];
Go to Build\Build and Analyze again, and you’ll see that there are no remaining issues.