views:

3669

answers:

8

Memory (and resource) leaks happen. How do you make sure they don't?

What tips & techniques would you suggest to help avoid creating memory leaks in first place?

Once you have an application that is leaking how do you track down the source of leaks?

(Oh and please avoid the "just use GC" answer. Until the iPhone supports GC this isn't a valid answer, and even then - it is possible to leak resources and memory on GC)

+4  A: 
  • Follow the rules for retaining and releasing (or use Garbage Collection). They're summarized here.

  • Use Instruments to track down leaks. You can run an application under Instruments by using Build > Start With Performance Tool in Xcode.

millenomi
Good answer. Both tips are definitely part of the solution. I'd like this post to become the complete A-Z of memory leak debugging. We'll see if that happens. ;-)
schwa
+8  A: 

The Instruments Leaks tool is pretty good at finding a certain class of memory leak. Just use "Start with Performance Tool" / "Leaks" menu item to automatically run your application through this tool. Works for Mac OS X and iPhone (simulator or device).

The Leaks tool helps you find sources of leaks, but doesn't help so much tracking down the where the leaked memory is being retained.

schwa
+2  A: 

I remember using a tool by Omni a while back when I was trying to track down some memory leaks that would show all retain/release/autorelease calls on an object. I think it showed stack traces for the allocation as well as all retains and releases on the object.

http://www.omnigroup.com/developer/omniobjectmeter/

Ashley Clark
+17  A: 

Use the LLVM/Clang Static Analyzer

To avoid creating memory leaks in the first place, use the Clang Static Analyzer to -- unsurprisingly -- analyse your C and Objective-C code (no C++ yet) on Mac OS X 10.5. It's trivial to install and use:

  1. Download the latest version from this page.
  2. From the command-line, cd to your project directory.
  3. Execute scan-build -k -V xcodebuild.

(There are some additional constraints etc., in particular you should analyze a project in its "Debug" configuration -- see http://clang.llvm.org/StaticAnalysisUsage.html for details -- the but that's more-or-less what it boils down to.)

The analyser then produces a set of web pages for you that shows likely memory management and other basic problems that the compiler is unable to detect.

If your project does not target Mac OS X desktop, there are a couple of other details:

  1. Set the Base SDK for All Configurations to an SDK that uses the Mac OS X desktop frameworks...
  2. Set the Command Line Build to use the Debug configuration.

(This is largely the same answer as to this question.)

mmalc
+10  A: 

Always use accessor methods; declare accessors using properties

You make life much simpler for yourself if you always use accessor methods to assign values to instance variables (except in init* and dealloc methods). Apart from ensuring that any side-effects (such as KVO change notifications) are properly triggered, it makes it much less likely that you'll suffer a copy-and-paste or some other logic error than if you sprinkle your code with retains and releases.

When declaring accessors, you should always use the Objective-C 2 properties feature. The property declarations make the memory management semantics of the accessors explicit. They also provide an easy way for you to cross-check with your dealloc method to make sure that you have released all the properties you declared as retain or copy.

mmalc
+13  A: 

Don't overthink memory management

For some reason, many developers (especially early on) make memory management more difficult for themselves than it ever need be, frequently by overthinking the problem or imagining it to be more complicated than it is.

The fundamental rules are very simple. You should concentrate just on following those. Don't worry about what other objects might do, or what the retain count is of your object. Trust that everyone else is abiding by the same contract and it will all Just Work.

In particular, I'll reiterate the point about not worrying about the retain count of your objects. The retain count itself may be misleading for various reasons. If you find yourself logging the retain count of an object, you're almost certainly heading down the wrong path. Step back and ask yourself, are you following the fundamental rules?

mmalc
I don't have edit powers, yet, but the rules to which you link have a redirect that could evaporate at any moment. If you'd update it with this link, it'd keep your good post fresh and relevant: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/index.html
Wayne Hartman
+1  A: 

First of all, it's vitally important that your use of [ ] and { } brackets and braces match the universal standard. OK, just kiddin'.

When looking at leaks, you can assume that the leak is due to a problem in your code but that's not 100% of the fault. In some cases, there may be something happening in Apple's (gasp!) code that is at fault. And it may be something that's hard to find, because it doesn't show up as cocoa objects being allocated. I've reported leak bugs to Apple in the past.

Leaks are sometimes hard to find because the clues you find (e.g. hundreds of strings leaked) may happen not because those objects directly responsible for the strings are leaking, but because something is leaking that object. Often you have to dig through the leaves and branches of a leaking 'tree' in order to find the 'root' of the problem.

Prevention: One of my main rules is to really, really, really avoid ever allocating an object without just autoreleasing it right there on the spot. Anywhere that you alloc/init an object and then release it later on down in the block of code is an opportunity for you to make a mistake. Either you forget to release it, or you throw an exception so that the release never gets called, or you put a 'return' statement for early exit somewhere in the method (something I try to avoid also).

danwood
Sorry Dan, but best practice is now considered to be to avoid autorelease, especially on resource-constrained platforms (see http://stackoverflow.com/questions/155964/what-are-best-practices-that-you-use-when-writing-objective-c-and-cocoa#175874).
mmalc
With the advent of the Clang static analyser (http://clang.llvm.org/StaticAnalysis.html), the problems you rightly identify of forgetting to release or over-releasing should typically be found easily enough.
mmalc
+1  A: 

You can build the beta port of Valgrind from here: http://www.sealiesoftware.com/valgrind/

It's far more useful than any static analysis, but doesn't have any special Cocoa support yet that I know of.

alex strange