Google+ Badge

Thursday, December 1, 2011

Android Out of Memory issues

The dreaded "Out of Memory error" with corresponding "Force Close" on your Android device is very frustrating. It was happening to our users from time to time but today I think I may have found the issue. I won't know for sure if this is a true fix until it is out in the field.

I have a couple of ways to acquire images in our app - you can take a picture with the camera or grab an existing image from the gallery. In either case I have to check out the image size and shrink it down to less than 1 meg of data via scaling, quality compression or both. It has to be less than 1 meg as I am holding the images in a SQLite blob to be sent to the server at a later time. I can't leave things in the gallery due to HIPAA rules and I can't trust the user to not delete the original image between pick it and transmit it time frames.

You can also view the image at any time within my app using a viewer I wrote that allows pinch zoom, drag scrolling, rotation and fit to window functionality. This is where things started to go awry.

If I opened and existing image, exited that activity then tried to capture an image from the camera there was a good chance I would get the out of memory issue. If I just took pictures but never viewed them or waited some amount of time before viewing them it might work just fine. This also depended on the device and version of the OS I was using. To find the issue I opened an image in the viewer then closed the viewer and did a heap dump via DDMS in Eclipse, converted that dump via hprof-conv in the android sdk\tools directory and loaded it up in MAT (memory analysis tool) under Eclipse. The Dominator Tree showed the ImageView of the closed activity to still be holding on to a weak referenced large bitmap. I guess the reference is not weak enough for the GC to kick it out of memory during the camera processing even though I was calling System.gc() before I started the camera bitmap manipulation.

To solve the issue I added the following to the image viewing activity:


/**
 * On the way out dump our images
 */
@Override
protected void onDestroy() {
  imageView.setOnTouchListener(null);
  imageView.setImageBitmap(null);
  System.gc();
  super.onDestroy();
}


Now after hitting the back button from the image activity I don't have a large weak reference to an image floating about in the heap. I have been able to view, take pictures, view, lather, rinse, repeat without any issues. I was running these test on a ASUS Transformer tablet running OS 3.2.1

I am also making sure I call recycle on the bitmaps I use during my scale / quality reduction routines during the post camera processing.

Probably a good idea to manually release any large images you use in your application as activities go away to avoid these problems. Right now I am not releasing all the smaller images I am using but it might be a good idea to make a sweep through the heap dump to see what else is sneaking around.

Not sure if the System.gc() call is even necessary and I know they recommend you don't call it but at this point I can't see it hurting anything and I am only doing it on activity destroy so I am leaving it in there for good luck and hoping I don't hear of any more OOM crashes in the field.