Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to compact memory in android to lower the high water mark?

Please note I do NOT have a memory leak. My question is about a subtler issue.

I recently wrote an android app which does image processing. The image is loaded as a Bitmap, then copied out in pixels, processed in a way that uses lots of memory (think Fourier transforms in floating point representations and stuff), then converted back into a bitmap and saved.

The problem is, through at least android OS 2.3, the total memory limitation (typically 16MB) is combined java and (externally stored) Bitmaps, and the java high water mark doesn't go down (that I can discern) even when the memory is free (successfully GC'd), which means when I go to allocate the final Bitmap, I am often "out of memory" even though by that point I have freed (and GC'd) most of the space. I.e., I never need the full 16MB at once, but the space left for Bitmaps appears to be 16MB minus the MAX historical java heap usage (as opposed to current usage).

I watched a tech talk by one of the android developers about memory issues and he implied this problem has been fixed in subsequent versions of the OS (they moved Bitmap memory into the java heap space), but in the meantime most of the people wanting to use my app are running 2.2 or 2.3.

Long story short, I am wondering if the java heap is ever compacted (de-fragmented, in effect) so that the high-water mark shrinks (and if so, how to make it happen)?

If not, then does anybody have another suggestion how to deal with this problem?

like image 467
Brandyn Avatar asked Jul 13 '11 12:07

Brandyn


2 Answers

Long story short, I am wondering if the java heap is ever compacted (de-fragmented, in effect) so that the high-water mark shrinks (and if so, how to make it happen)?

Whatever its behavior is, it most certainly is not under your control.

If not, then does anybody have another suggestion how to deal with this problem?

Ideally, reuse your own Bitmaps. You don't indicate what "processed in a way that uses lots of memory" really is. However, if it does not change the dimensions or bit depth of the image, copy the data back out to the original Bitmap rather than allocating a fresh one, if you can.

Image processing on Android 2.x is one of the few places where I can see justifying using multiple processes. You will add overhead for schlepping the image data between processes, but the other process has its own heap (Java and native), so this may give you more "elbow room".

like image 153
CommonsWare Avatar answered Sep 28 '22 13:09

CommonsWare


So far, no indication that there is any way to compact the memory.

Here is my workaround, which is suboptimal but much better than the behavior before:

I now intentionally hold on to the original Bitmap while I am doing my processing, and then recycle() and null it, and GC(), but not until just before allocating my output Bitmap.

What this does is reserve external (Bitmap) space, and cause my application to run out of java heap (during processing, before calling recycle()), which I can at least catch and handle by retrying on a smaller image. (Before, everything seemed to be fine until I tried to save, but by then it was too late and with no way to recover.)

Technically this limits my max image size to less than I should be able to do with the allotted memory (because I need to reserve space in the heap and external at the same time when in truth I never need both together), but at least I can still handle a reasonable image size.

What was happening before is I would free and recycle the Bitmap early which allowed the high water mark on the java heap to use up essentially all of my memory allotment, meaning from that point forward I couldn't open or create any more Bitmaps at all (other than tiny thumbnail sizes sometimes).

Imo, this is a major bug in the way android handles Bitmap memory, but I believe it is fixed in newer versions of the OS so hopefully I can disable this workaround conditional on the OS release.

like image 44
Brandyn Avatar answered Sep 28 '22 12:09

Brandyn