Managing Memory when working with Bitmaps

One of the (very few) errors I had with Jumping Jack was an OutOfMemoryError that happened if you went back and forth from the game to the main screen a few times. On  my phone, an HTC Hero, it happened after doing this about 8-9 times, on a friend’s Motorola Milestone/Droid 2 I could do the same 50 times without it happening.

The OutOfMemory always occurred when loading the large background bitmap. The strange thing about it was that ddms only showed around 3 MB of heap memory being allocated, and as you may know, the limit for a process on Android is 16 MB of heap.

Digging deeper (aka. Googling) I found out that the memory for bitmaps is allocated natively and not as part of the heap, and that the 16 MB limit includes heap and non-heap memory. So that’s one elucidated mystery.

The next thing to do was a memory profiling session, to find out where I was leaking the bitmaps. Well, surprise surprise, it turned out I wasn’t! After more research, it turns out that deallocating non-heap memory is a rather difficult task for the Android GC, and that it actually takes two runs of the GC to clear-out things such as memory used by bitmaps (see the 2nd link at the end of the article).  The author recommended constructs such as:

try {
    BitmapFactory.decodeBitmap(…);
} catch (OutOfMemoryError oome) {
    System.gc();
    BitmapFactory.decodeBitmap(…);
}

as well as giving the GC a helping hand now and then by explicitly calling System.gc().

This didn’t help much either, but on further reading I found out there’s a method called recycle() that you can call on a Bitmap, and which frees the memory used for storing the pixel data for it. So this finally solved my problem – I’m now calling recycle on my bitmaps when my activity gets destroyed – no more OOMs.

Relevant links:

http://www.mail-archive.com/android-developers@googlegroups.com/msg82996.html
http://kohlerm.blogspot.com/2010/02/android-memory-usage-analysis-slides.html