views:

2116

answers:

5

I have an iPhone app that is running great in the simulator. It responds well to the memory warnings by getting rid of everything that is not absolutely essential. When I run it on the device, it runs well. But after a certain amount of usage it crashes with error code 101 - which, from what I can tell, is the OS killing it due to memory usage. I can see the memory warning (I'm logging it), and my app responds to it, but dies shortly thereafter.

If I look at the app in Instruments (either on the device or in sim), it doesn't find any leaks. In addition, the net memory usage is in the range of 600-700k bytes. Transitioning from the different views of my app increases memory usage (as expected), but when the views and controllers are released and dealloc'd, the memory usage never quite goes as low as it was. However, the addition is usually only something in the range of 1000-2000 bytes. So while Leaks shows me no leaks, I suspect there is an issue somewhere. I've also looked at all of the objects I'm allocating, and all of them seem to be reclaimed as expected. The only objects I see that keep increasing are GeneralBlock-N (where N is some number)

Should I not pay any attention to Instruments net usage figure? What would be the next steps in trying to diagnose the issue?

ADDED: I'm not making any calls to malloc() or any CoreFoundation libraries that would return a buffer that I'm responsible for. The only non-Obj-C calls I'm making are logging statements to NSLog.

+6  A: 

One quick thing to try is running the Clang static analyzer. This will find some, but not all, issues in your code that you might be missing. It checks the code at compile time, so it's by no means infallible, but will almost certainly find most glaring problems.

Ben Gottlieb
+1 for Clang. It's found so many memory leaks that I had missed. Here's the tutorial that worked when I was struggling to set it up: http://www.oiledmachine.com/posts/2009/01/06/using-the-llvm-clang-static-analyzer-for-iphone-apps.html
bbrown
+3  A: 

You should also run your application with the memory monitor instruments to see overall system usage on the device.

wisequark
Sorry if this wasn't clear in the original question, but I've tried that as well. That's what is telling me that the net usage is somewhere in the 600-700k bytes range. And I can see in that tool that all of my objects are being cleaned up as well.
Bdebeez
Scratch that last comment - I had been using ObjectAlloc. Thank you very much for the tip - the Memory monitor DOES show that I am using an awful lot of memory. Now I need to find out why...
Bdebeez
Just because you aren't creating your own foundation objects doesn't mean they aren't being created for you as a result of things like an NSArray or NSURLConnection
wisequark
+1  A: 

Leaks only finds memory that is not referenced by anything, but still retained.

What you are seeing is that you have left memory retained, and still referenced by something.

One thing to look for especially, is that if you have passed a reference of a class to something else as a delegate that you free it in your dealloc method.

Similarly, if you have subscribed to any notifications you should unsubscribe in viewWillDisappear: (if you use the general unsubscription method in a view controller do not forget to re-subscribe to the memory warning notification.

Timers are the same way, deactivate them when a view goes away and re-enable them when the view comes back (unless of course you need a timer running the whole time your application is running).

Basically be suspicious of anything you give a reference of a class to, and try to figure out how you might eliminate that link whenever possible (either in dealloc or viewWillDisappear: or both).

Kendall Helmstetter Gelner
+1  A: 

Here's a summary of what I've learned (thanks to some excellent answers and comments):

  • Object Allocation is NOT the same as Memory usage. The answer to my question about ObjectAlloc's net bytes element is that you shouldn't be paying attention to it - at least not when determining issues with the amount of memory you are using or whats causing it to crash. It doesn't reflect the true memory usage of your application.
  • My amatuerish guess is that ObjectAlloc only shows you the memory taken up by the direct object itself. So if you have an UIImageView, it takes up just a handful of bytes to store the various properties, but it might be pointing to an image in memory taking up a bunch of space. Therefore, looking at ObjectAlloc is helpful only in making sure you're not creating and keeping objects around, it won't give you an idea of how much memory you're using or how much you can use before crashing.
  • MemoryMonitor will give you the total memory usage. You can constrain it to viewing only your app's usage by using the search tool in the bottom right of the Instruments window.
  • Both ObjectAlloc and Memory Monitor (as well as the Leaks tool) are plugins for Instruments - just in case thats not obvious to someone else. You can launch Instruments from within XCode by doing Run -> Start with Performance Tool. Once inside of Instruments, you can open the Library and add new plugins to monitor different aspects of performance.
Bdebeez
Great. Does that mean you have solved it? Or is this still running?
Phil Nash
Still a bug :( I've asked a much more specific question here - http://stackoverflow.com/questions/289360/problem-deallocing-memory-used-by-uiimageviews-with-fairly-large-image-in-an-ui
Bdebeez
I've fixed my specific bug - the above mentioned URL contains the solution
Bdebeez
A: 

One thing to look for is circular references.

(I don't want this to sound patronising - just want to make sure I'm being clear:) If object a refers to object b and object b refers to object a, there may not be a reported "leak" because all the memory is still referenced - but this may be an orphaned island of objects, seperated from your app and never reclaimable. Of course it may involve more objects ( a refers to b, b refers to c, c refers to a, etc).

If you're building up a graph of objects somewhere, and there are any back or cross references, be sure to break the circles if you release the root (there are different ways of doing this. The simplest is probably to make sure each class in question has a releaseAll method, or similar - which calls releaseAll on it's child objects, then releases the child objects - but this isn't always the best solution).

Phil Nash