Alex Rivera | Logout

Bitmap recycle with largeHeap enabled

Asked 2012-10-03T20:42:19.887
10

Before enabling largeHeap option, I was handling large bitmaps and it's consume almost the entire memory available for the application, and recycling it over navigation and loading new ones works round on almost the full heap available. However when some operations needs a bit more memory the application crashes. So I enabled largeHeap=true to have a bit more memory.

But doing this has a unexpected behavior, it's looks like that recycle() method of bitmaps do not work most of times, and the application that worked in 58Mb of memory (and exceeds sometimes throwing a OutOfMemoryException) now consumes memory exponentially and keeps growing (for now the test I did came to 231Mb allocated memory), the expected behavior is that the memory management keeps working and the application will not use more than 60Mb.

How can I avoid that? Or efficiently recycle bitmaps?

EDIT: Actually, I made it give a OutOfMemoryError when allocating more than 390Mb of memory on the device. Reading GC_* logs shown that only GC_FOR_ALLOC that freed 3.8Mb sometimes, but almost never other GC runs freed something.

Edit
Report

1 Answer

1

To address your dilemma, I believe this is the expected behaviour.

If you want to free up memory you can occasionally call System.gc(), but really you should for the most part let it manage the garbage collection itself.

What I recommend is that you keep a simple cache (url/filename to bitmap) of some sort which keeps track of its own memory usage by calculating the number of bytes that each Bitmap is taking up.

/**
 * Estimates size of Bitmap in bytes depending on dimensions and Bitmap.Config
 * @param width
 * @param height
 * @param config
 * @return
 */
public static long estimateBitmapBytes(int width, int height, Bitmap.Config config){
    long pixels=width*height;
    switch(config){
    case ALPHA_8: // 1 byte per pixel
        return pixels;
    case ARGB_4444: // 2 bytes per pixel, but depreciated
        return pixels*2;
    case ARGB_8888: // 4 bytes per pixel
        return pixels*4;
    case RGB_565: // 2 bytes per pixel
        return pixels*2;
    default:
        return pixels;
    }
}

Then you query how much memory the app is using and how much is available, maybe take half of that and try to keep the total image cache size under that, by simply removing (dereferencing) the older images from your list when your are coming up against this limit, not recycling. Let the garbage collector clean up the bitmaps when they are both derefrrenced from your cache and are not being used by any views.

/**
 * Calculates and adjusts the cache size based on amount of memory available and average file size
 * @return
 */
synchronized private int calculateCacheSize(){
    if(this.cachedBitmaps.size()>0){
        long maxMemory = this.getMaxMemory(); // Total max VM memory minus runtime memory 
        long maxAllocation = (long) (ImageCache.MEMORY_FRACTION*maxMemory);
        long avgSize = this.bitmapCacheAllocated / this.cachedBitmaps.size();
        this.bitmapC
answered 2012-10-15T02:41:53.567

Your Answer