views:

429

answers:

4

I have been hunting down memory leaks for some time in my app. As of right now, as I flip back and forth between two views while watching the memory monitor instrument, the real memory fluctuates between 5 and 6 megs. This is all fine -- as far as I can tell everything is getting released properly when I pop back off a view. However, the virtual memory continues to increase and my available real memory drops rapidly every time I push the view back onto the view stack (even though the real memory usage of the app isn't increasing). Eventually, this all leads to an out of memory crash. Is this a telltale sign of any specific issue, or am I just missing a memory leak somewhere?

EDIT: The odd part is, I get an out of memory crash while the app is still only using up about 5 megs of real memory.

A: 

Have you used the "Leaks" Performance Tool? And check out the logs in Organizer to see if there's anything there.

Also look into the dealloc for the view controllers and make sure you are properly releasing all of it's objects?

Michael Kernahan
I used Leaks. It didn't find anything. I'm checking out the device log in the organizer right now. There are all sorts of low memory logs from my testing, but I don't know how to make use of any of the info.
Artelis
Could you implement `- (void)didReceiveMemoryWarning` in your view controllers? The memory symptoms around pushing your view controller sound like you could be creating new instances without releasing all of the old ones.
Michael Kernahan
already implemented, and the view controllers are all autorelease.
Artelis
hmmm... maybe look into the dealloc for the view controllers and make sure you are properly releasing all of it's objects? Maybe add a break point and check the retainCount of them all. You can do this in the console via `po [<variableName> valueForKeyPath:@"retainCount"]`
Michael Kernahan
Ah ha! I haven't totally solved the problem, but this has definitely pointed me in the right direction. Thank you!!
Artelis
Cool, I'll add that info to my original answer.
Michael Kernahan
turned out to be one of the scroll views not getting released. Only found by checking the retainCount of EVERYTHING! Thanks!
Artelis
No! Calling -retainCount is a *horrible* way of debugging this kind of problem. It is misleading and inefficient.
bbum
Artelis: Just because `retainCount` said it hadn't been released yet doesn't mean it hasn't been autoreleased. If it has been autoreleased, it *will* get released later, and adding a release-now message would be an over-release. This is what @bbum means by `retainCount` being “misleading”. I'd say you have 50:50 odds on whether you have fixed this bug or added another. Always use the Allocations and/or Leaks instruments to debug this sort of thing. The new heapshots feature would be the ideal way, since you say Leaks didn't find anything. @bbum wrote a good article about it: http://j.mp/brTKo1
Peter Hosey
Thanks bbum et al for the info!
Michael Kernahan
+2  A: 

Anyway, you can also use the "Build -> Build and analyze" option to find suspicious non-conventional code.

Prcela
+1, the static analyser is very useful.
dreamlax
Better yet, turn on the “Run Static Analyzer” build setting, so that Xcode will run the analyzer every time you build.
Peter Hosey
+8  A: 

Do not use -retainCount.

The absolute retain count of an object is meaningless. It is an implementation detail. It may be influenced by many factors well beyond your code.

You should call release exactly same number of times that you caused the object to be retained. No less (unless you like leaks) and, certainly, no more (unless you like crashes).

See the Memory Management Guidelines for full details.


In this specific case, you are leaking memory but in a way that leaks can't find it. The objects that are leaked are still connected to your overall application's object graph somehow. Maybe through a notification, maybe through delegation, doesn't matter -- leaks sees the reference and concludes that the object might still be live.

Use the Allocations Instrument. Configure it to only track live allocations (since you don't care about objects that have been deallocated). Do some stuff with your app. Check out what Allocations knows about and explain why all those objects should stick around. You can use the data mining facilities to filter down to just your objects.

bbum
A: 

Circular references also won't be counted in Leaks but you can track those in Allocations. Best bet is to fire up Allocations and get to a state where you think everything should be gone (or certain objects should be). If they're hanging around go dive in to them and look at where they've been retained and sort out the proper memory ownership/releasing.

As for Allocations, there are some things that it doesn't track that can affect the overall memory. Some of the things include some CGImage backing stores, some CoreAnimation stuff and some database stuff.

xmlhack
Circular references in object graphs otherwise isolated from the reachable object graph will be counted; leaks does do cycle detection but, obviously, a false positive on any object in a graph causes the whole graph to be reported as not leaking and, thus, circular references effectively increase the chance of leaks not reporting all the involved objects.
bbum