Fix and a Solution
Thank you to everyone who has purchased iHappyBirthday. Reaction to iHappyBirthday has been quite positive. However, we’ve been receiving reports of random crashes. We actually know why this happens. In a previous, unreleased version of iHappyBirthday, we displayed an alert message to the user telling him or her that the system is running low on memory; and that continuing without freeing up memory may crash the application.
But we removed this message because according to our tests, the phone did not reach such a low level of memory that it would cause it to crash. However, iHappyBirthday 1.1 uses a little bit more memory than 1.0, and that seems to have pushed it over some threshold which is making it more prone to crashing. We are happy to say that we have solved this problem by drastically reducing the memory usage. We have submitted version 1.1.1 and it should be available soon for download. But in the mean time, please follow the workaround from our support page.
Technical Mumbo Jumbo: iPhone Memory Management System
I’m writing this for the benefit of other developers who may be facing similar memory problems. Or if you are not a developer and just happen to be a glutton for pain, then please read on. Our application was not using that much memory, but when other applications (like Safari) were taking up over 20 MB of RAM, it would cause our application to crash due to the phone running low on memory. The following were my observations while chasing down this problem.
When the iPhone runs low on memory, it will start freeing memory from background applications like Safari. But why then was our application still crashing? This was because the rate at which our application was using up the memory was greater than the rate at which the operating system was freeing up the memory. Ultimately, it comes down to this simple fact:
“Always minimize memory usage.”
It’s not very enlightening, but that’s the fact of the matter. Looking at the Activity Monitor in Instruments, I noticed that the memory used by Safari continued to decrease bit by bit over time as iHappyBirthday was running. And then eventually, Safari was entirely removed and all resources freed. However, if iHappyBirthday was too aggressive in its memory usage, even though the OS was freeing up memory, it could not outpace the rate at which iHappyBirthday was requesting memory. The result? Crash.
For version 1.1.1, the memory use was halved. It was achieved by not using the UIImage’s imageNamed message and by intelligently loading resources. It turns out that if you use imageNamed, the resources are cached into the memory and the iPhone does not do a very good job of releasing the cached memory. For version 1.1.1, imageWithContentsOfFile was used in conjunction with imageNamed. And for the most part, the caching was handled by the application rather than the iPhone SDK.
It was interesting to see how the memory management system behaves on the iPhone. And even more enlightening to learn about the pitfalls of using UIImage’s imageNamed routine. In fact, the documentation for this routine states,
“This method looks in the system caches for an image object with the specified name and returns that object if it exists. If a matching image object is not already in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.”
But of course, I never looked at the documentation before using this. Had I looked at it, I could probably have avoided all this mess.
So always remember to RTFM!