Fixing iPhone memory leaks, getting started - objective-c

I am an experienced C/C++ programmer, and familiar with memory management issues. I've also shipped a couple small iPhone apps in the past. I am attempting to check my latest app for memory leaks, and I can't make any headway, because there are so many of them. Just starting the app and viewing the first screen shows over 12,000 leaks.
I know I've probably overlooked various things, but I was reasonably cautious in writing the code. I made attempts to release everything I alloc'ed in my dealloc method. It is like my app delegate never gets released, because I can see a couple things that are only alloc'ed once, in the app delegate's init method. They are never modified, and are released in the dealloc method.
This app is built around a tab controller, with around 15 views mainly set up using Interface Builder.
Any help would be appreciated.

Instruments of apple is pretty advanced.. it can show you the exact method that originally created the memory leak, I suggest taking a look at those methods and carefully reading your code ,there usually is this line of code in there and you thought OMG how could I be that stupid.
If that doesn't help, try to "Analyze" with xcode, its pretty good at finding errors and leaks in your code and saved my * a couple of times.

Related

iOS6 backwards compatibility

I want to support both users running iOS5 and iOS6. But for instance UIViewController's method -viewDidUnload is deprecated in iOS6. So how would I use it for users running iOS5, but not for users running iOS6?
You can continue having this method in your code, it will just not be called. If you really wish to have it called, you can invoke it in didReceiveMemoryWarning. In fact, move the code there for old iOS as well.
Other changes that might interest you are related to rotation. You can implement both the new iOS6 methods as well as keep the old ones, and they will not interfere with each other.
while it is indeed okay to continue to have the call to viewDidUnload …
the information from the WWDC talks on this is that you should not only not have viewWillUnload and viewDidUnload for iOS6 situations, but that you should just go ahead and remove it for code that will be used for both iOS 5 and iOS 6.
the justification given by the apple dude narrating the WWDC slide presentation is that apple did some amount of study, and concluded it solved a whole class of crashers that were avoidable, and dealt only w/tiny bits of memory.
the recommendation is that anything that is currently in one of these that's absolutely necessary to your app should probably be appearing in viewDidDisappear:animated: or in dealloc (for large shared stuff that needs to give back memory), and that there will be many cases where neither is necessary.
(not an advocate, just relaying what i learned from the WWDC material on the subject …)

Problems with memory management, autorelease, permanent heap is sometimes 250+ kb on iOS

I'm really pulling my hair out on this one, it seems that I'm having severe issues with memory management on an iOS app.
Here's the case: first I load table. When the user taps a cell, it presents a complicated view. The most memory consuming about the view is that it's loading 20+ UIImages of 500x500. There are two other tabs in that view, loading a list of media (those UIImages, but then in a table) and another simple table.
When I return back to the first table view, apparently over 250 kB is still allocated on heap. I know the view is complicated, but there's no reason to keep so much memory alive. And well, guess what, when I do switch to the view a lot, eventually the app runs out of memory and gets killed.
What I tried to solve it:
Fix all Analyze issues, so according to that there are no leaks anymore.
Check all inits again for releasing, making use of autorelease where possible.
Checking all the memory leaks using Instruments -> Leaks. In a runtime of 6, I get not more than 2 or 3 leaks.
Last, Instruments -> Allocation, checking the heap. This is what bothers me, between two marked heapshots I get a difference of 250+ kB. I've looked into it, using the detailed views. I can't get my head around it: when it's pointing to one of my methods/classes, I'm pretty sure everything in there is either released or autoreleased. It's also pointing to a lot of not-mine (say QuartzCore) methods/classes.
Also, I don't understand why autorelease is not autoreleasing. I mean, it sometimes looks like an object that is marked for autoreleasing, is released way too late. I haven't created any NSAutoreleasePools myself, so is it possible that the pool is drained only when the runtime stops? How can I periodically drain the pool (even if it's not mine).
Any help is greatly appreciated.
Kind regards,
Reinder
Used this for the heap checking: http://www.friday.com/bbum/2010/10/17/when-is-a-leak-not-a-leak-using-heapshot-analysis-to-find-undesirable-memory-growth/
Are you using imageNamed to load your images - this method will keep all images cached in memory. Try initWithContentsOfFile instead.
Watch out though; initWithContentsOfFile: won't cache at all so if you use this method a lot for the same image then you should be using imageNamed:!
I think you might want to try to optimize your design first and read guides for efficent memory management. A better understaning of the components and the runtime helps more than tracking memory allocations and will make it easier to find the leaks.
First you should always use release. Only use autorelease when necessary.
Make sure you follow the guidelines for UITableView implementations and efficient management of UITableViewCells (lazy loading, cell reusing etc.).
Check if you have retain-cycles (retained view controllers won't be deallocated).
Track the deallocation of your view controllers and objects
Don't keep stuff in memory you don't need anymore.
Don't load stuff you don't need right now.

Unexplained crashes iOS

I'm currently working on a game for iPhone/iPad using Cocos2D.
On the simulator it works fine and can run for hours, without any problems.
But on a device, it runs for some time and then just crashes out of nowhere. The debug console gives no error message, typing in "bt" just returns "No stack." and it doesn't generate a crash report.
It mostly crashes when loading the main menu or a new level but it can happen while playing a level as well.
Any ideas on how to debug this?
You should really read about memory management in objective-c
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html
When I first switched to programming in objective-c (from C#/Java background), I had a lot of problems too. Once I understood memory management in objective-c, I rarely have those kind of problems. I don't use arc.
Whenever you alloc & init an object, the retain count is 1. You should remember to release these objects at some point. If you use other methods, then you get an autorelease object. That is the convention.
The time you will save is really worth it.

I can't track down this leak. Audio Toolbox

I have gone over a silly amount of forum posts and questions here. while i would love to take this advice: http://www.cocos2d-iphone.org/forum/topic/2003 I suppose i just don't trust 'them' as much as this community.
so, I ask, is this a 'negligible leak' if it only seems to happen once when i push a view onto the root view controller?
The core audio libraries have always given me unfixable memory leaks. Just ignore them because they are Apple's fault.
There's 416 bytes leaked there but if it only happens once then it's nothing to worry about.
With my code, the AVAudioPlayer class leaks each time I call the play method. It's rubbish. Luckily it's only a small leak.

Avoiding, finding and removing memory leaks in Cocoa

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)
In XCode 4.5, use the built in Static Analyzer.
In versions of XCode prior to 3.3, you might have to download the static analyzer. These links show you how:
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:
Download the latest version from this page.
From the command-line, cd to your project directory.
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:
Set the Base SDK for All Configurations to an SDK that uses the Mac OS X desktop frameworks...
Set the Command Line Build to use the Debug configuration.
(This is largely the same answer as to this question.)
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?
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.
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.
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.
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/
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).
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.
Obviously you need to understand the basic memory management concepts to begin with. But in terms of chasing down leaks, I highly recommend reading this tutorial on using the Leaks mode in Instruments.