Arturs Vancans
Arturs Vancans

Reputation: 4640

Android Bitmap memory leak

I am trying to create cached image system for Android but the memory consumption just grows and grows. I looked through Android website for some ideas, but the issue just doesn't want to disappear.

Below is my code of getting the image from SD card, setting it and later destroying. What am I doing wrong?

WeakReference<Bitmap> newImageRef;
    public void setImageFromFile(File source){
        if(source.exists()){

            Bitmap newImage = BitmapFactory.decodeFile(source.getAbsolutePath());
            newImageRef =   new WeakReference<Bitmap>(newImage);
            if(newImage != null){
                this.setImageBitmap(newImage);
            }
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        Bitmap newImage = newImageRef.get();
        if (newImage != null) {
        newImage.recycle();
        newImage = null;
        }


        Drawable drawable = getDrawable();
        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            Bitmap bitmap = bitmapDrawable.getBitmap();
            if (bitmap != null){
            bitmap.recycle();
            }
        }
        this.setImageResource(0);
        newImage = null;
        newImageRef = null;
        System.gc();


        super.onDetachedFromWindow();
    }

Upvotes: 2

Views: 7183

Answers (3)

Patrick
Patrick

Reputation: 35234

As of this code it's hard to check if there is a detailed bug as this seems to cleary be a simplifyed version of the "full cache". At least the few lines you provided seem to look ok.

The main issue is the GC seems to be a little strange when handling Bitmaps. If you just remove the hard references, it will sometimes hang onto the Bitmaps for a little while longer, perhaps because of the way Bitmap objects are allocated. As said before recycling is not necessary on Android 3+. So if you are adding a big amount of Bitmaps, it might take some time until this memory is free again. Or the memory leak might be in anothe part of your code. For sophisticated problems like that its wise to check already proven solutions, before re-implementing one.

This brings me to the second issue: the use of weak refrences. This might not target the main problem, but is generally not a good pattern to use for image caches in Android 2.3+ as written by android doc:

Note: In the past, a popular memory cache implementation was a SoftReference or WeakReference bitmap cache, however this is not recommended. Starting from Android 2.3 (API Level 9) the garbage collector is more aggressive with collecting soft/weak references which makes them fairly ineffective. In addition, prior to Android 3.0 (API Level 11), the backing data of a bitmap was stored in native memory which is not released in a predictable manner, potentially causing an application to briefly exceed its memory limits and crash.

The way to go now is to use LRU Caches, which is explained in detail in the link provided about caching.

Upvotes: 0

user2448027
user2448027

Reputation: 1638

Try to use Drawable.setCallback(null);. In Android 3.0 or newer, you don't even need to recycle because of more automatic memory management or garbage collection than in earlier versions. See also this. It has good information about bitmap memory management in Android.

Upvotes: 1

blganesh101
blganesh101

Reputation: 3695

If you are using Android version >3.0 you dont have to call recycle()as the gc will clean up bitmaps on its own eventually as long as there are no references to it. So it is safe to remove recycle calls. They do nothing much here.

The code which you posted looks neat but are you sure there the leak is not happening somewhere else. Use Android Memory Analyzer tool to see where the leak is happening and then post the info.

Good luck.

Upvotes: 2

Related Questions