Android Bitmaps and Memory Leaks

I wanted to share some info that I have been learning about in my latest project. It seems that Android has an interesting way of memory management for Bitmaps. Drawables seem to act normal and get cleaned up with the garbage collector, but Bitmaps are apparently not in the normal application heap. This causes problems… for me anyway. There is an awesome article about it here if you want to learn more about it and how to find memory leaks in general.

Basically the solution to this problem is to manually recycle any Bitmaps you create once you are done using them. This seems pretty simple because you can basically call recycle() on all your bitmaps in the onDestroy() hook in your Activity. However, most of the time you have a separate thread running that is using these image resources. If you recycle your bitmaps in the Activity, there is no guarantee that your background thread won’t come searching for these resources before it dies.

My solution: I created an “ImageManager” class.

class ImageManager {
    private HashMap<Integer, Bitmap> mBitmaps;
    private HashMap<Integer, Drawable> mDrawables;
    private Context mContext;

    private boolean mActive = true;

    public ImageManager(Context c) {
        mBitmaps = new HashMap<Integer, Bitmap>();
        mDrawables = new HashMap<Integer, Drawable>();
        mContext = c;
    }

    // We need to share and cache resources between objects to save on memory.
    public Bitmap getBitmap(int resource) {
        if (mActive) {
            if (!mBitmaps.containsKey(resource)) {
                mBitmaps.put(resource,
                    BitmapFactory.decodeResource(mContext.getResources(), resource));
            }
            return mBitmaps.get(resource);
        }
        return null;
    }

    public Drawable getDrawable(int resource) {
        if (mActive) {
            if (!mDrawables.containsKey(resource)) {
                mDrawables.put(resource, mContext.getResources().getDrawable(resource));
            }
            return mDrawables.get(resource);
        }
        return null;
    }

    public void recycleBitmaps() {
        Iterator itr = mBitmaps.entrySet().iterator();
        while (itr.hasNext()) {
            Map.Entry e = (Map.Entry)itr.next();
            ((Bitmap) e.getValue()).recycle();
        }
        mBitmaps.clear();
    }

    public ImageManager setActive(boolean b) {
        mActive = b;
        return this;
    }

    public boolean isActive() {
        return mActive;
    }
}

This does two things: first, it makes it easy to recycle all your bitmaps and keep track of when you have recycled them to shut down your app, and second, It enables you to share repeated resources.  In my app, I have images that I use many instances of. Previously I would instantiate a new Drawable or Bitmap for these using up memory for a resource I already had in memory.  When you get a resource from the ImageManager, because it keys on the drawable ID, it checks to see if it is already available before loading it again.

It also makes it a little easier to get an image.  the ImageManager object you create will have to be passed to every object you want to use it, but when it’s available just call im.getDrawable(R.drawable.whatever) to get your Drawable.

You will still have the problem of the background thread trying to access assets after they are recycled.  To avoid this you will have to either check every time to see if the ImageManager is still active, or (the lazy way) catch the NullPointerException it throws when it tries to draw.

27 Responses to “Android Bitmaps and Memory Leaks”

  1. LM says:

    Thank you for the post. I’ve not tried yet but this is what i wanted

  2. Cory Trese says:

    It seems like there is a code error here with “mGame”

  3. Nate says:

    Cory,
    You’re right. There were a couple references outside code that I missed. I’ve updated the code so that you can just pass your application’s Context to it on construction. I haven’t tested it yet, but it should make it more independent.

  4. Mike says:

    Hi Nate,

    Excellent class thanks for sharing. Could you elaborate more on how to “check every time to see if the ImageManager is still active”. I’m not getting that.

    Thanks

    Mike

  5. Mike says:

    Hi Nate,

    That was easy, what if you need to reference the drawable by ImageView Id?

  6. Mike says:

    Ok now how to avoid this

    03-19 11:28:51.701: WARN/dalvikvm(14369): threadid=1: thread exiting with uncaught exception (group=0×40015560)
    03-19 11:28:51.721: ERROR/AndroidRuntime(14369): FATAL EXCEPTION: main
    03-19 11:28:51.721: ERROR/AndroidRuntime(14369): java.lang.NullPointerException
    03-19 11:28:51.721: ERROR/AndroidRuntime(14369): at com.company.app.util.ImageManager.getDrawable(ImageManager.java:39)
    03-19 11:28:51.721: ERROR/AndroidRuntime(14369): at com.company.app.LevelManager.showScoreDialog(LevelManager.java:226)
    03-19 11:28:51.721: ERROR/AndroidRuntime(14369): at com.company.app.LevelManager.access$3(LevelManager.java:214)
    03-19 11:28:51.721: ERROR/AndroidRuntime(14369): at com.company.app.LevelManager$1.handleMessage(LevelManager.java:202)
    03-19 11:28:51.721: ERROR/AndroidRuntime(14369): at android.os.Handler.dispatchMessage(Handler.java:99)
    03-19 11:28:51.721: ERROR/AndroidRuntime(14369): at android.os.Looper.loop(Looper.java:123)
    03-19 11:28:51.721: ERROR/AndroidRuntime(14369): at android.app.ActivityThread.main(ActivityThread.java:3839)
    03-19 11:28:51.721: ERROR/AndroidRuntime(14369): at java.lang.reflect.Method.invokeNative(Native Method)
    03-19 11:28:51.721: ERROR/AndroidRuntime(14369): at java.lang.reflect.Method.invoke(Method.java:507)
    03-19 11:28:51.721: ERROR/AndroidRuntime(14369): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
    03-19 11:28:51.721: ERROR/AndroidRuntime(14369): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
    03-19 11:28:51.721: ERROR/AndroidRuntime(14369): at dalvik.system.NativeStart.main(Native Method)

  7. Mike says:

    This is how I’m calling it

    final ImageView animDialog = (ImageView) myDialog.findViewById(R.id.dialog_my_panel);

    animDialog.setBackgroundDrawable(ImageManager.getDrawable(R.drawable.my_panel));

  8. Heartache says:

    Thank you very much for your guidance.

  9. shubham says:

    hello Nate, Thanks for sharing your knowledge, In my same app seen is something difference.
    I am drawing multi Bitmap images over the canvas and after an limit i got OutOfMemory Exception.
    Here how i can free memory for non-top images . Because Bitmap images stl showing on Canvas.

    pls suggest ..thanks again

  10. shubham says:

    hello ,

    I am drawing multi Bitmap images over the canvas , nw when I invalid an single view so all views got invalidate(means redraw again).
    Is it possible to invalid only single view .

    pls suggest me .

    Thanks

  11. Cory Trese says:

    Thanks again, this code has been really helpful. My memory management issues are greatly reduced =)

  12. Venu says:

    Hi,

    Can you please give me an example of how to reuse the bitmaps and drwables set in hashmap. No need to give entire program, just give me a snippet of code to understand the logic behind it.

    Thanks’
    venu

  13. Eugen says:

    Hello Nate!

    I’ve implemented something almost the same to your’s, but I stil have problems with accessing recycled bitmaps by children of ListView or GridView. any suggestion how to avoid such kind of problems?
    PS. In adapter i get bitmaps from ImageManager, when i leave the activity i recycle all of them. I’ve tried to set adapter = null, but it makes the list to disappear (it’s logic) and it’s does not look nice. Any suggestions will be appreciated.

    Thanks in advance!
    Eugen

  14. Raul says:

    Please, can you give me an example on how to use this class from an Activity? I’ve spend A LOT of time on this and still have the outofmemory …

    THANKS!

  15. anon says:

    Caching Drawables also carries the potential of memory leaks unless the cache and drawables dies with the activity or an activity state change, or you specifically clear it’s references to views and/or context.

  16. Nate says:

    Yeah, that’s why there’s the recycleBitmaps() method. It’s my understanding that as long as you recycle your bitmaps in your onDestroy(), everything else will be taken care of with the GC.

  17. test1 says:

    Thanks so much for including me in your list of fabulous bloggers!

  18. [...]  http://blog.pseudoblue.com/2010/08/15/android-bitmaps-and-memory-leaks/ 本文链接: Bitmaps图片泄露问题 版权所有: 非特殊声明均为本站原创文章,转载请注明出处:开发者 订阅更新: 您可以通过RSS订阅我们的内容更新 [...]

  19. [...] taking up valuable application memory. If LruCache can’t resolve the problem you can try this:ImageManager ,in the class ImageManager, it has a method recycleBitmaps. This entry was posted in android [...]

  20. game mobile says:

    Hello There. I discovered your weblog the use of msn. This is a really neatly written article. I will make sure to bookmark it and return to read more of your helpful information. Thank you for the post. I’ll definitely return.

  21. 楽天 ショルダーバッグ ポロシャツ 長袖 レディース http://wangtongk.nixonjpdonideal.org/

  22. Spot on with this write-up, I truly believe that this site needs a lot more attention.
    I’ll probably be returning to read through more, thanks for the information!

  23. e says:

    It’s a nice post.

  24. Ginkgo works by improving the blood flow to the
    smell vessels deep within the brain, which increases all of the brain’s functions,
    such as alertness, mood, concentration and cognitive ability.
    Vitamin B12, folate and niacin are some of the essential requirements for the brain
    and they are found in ample amounts in meat, eggs and dairy products.

    Vitamin B6 aids in the synthesis of DNA and RNA by maintaining the proper cell division and preventing cell abnormal growth such as peritoneal
    cells developing into endometrial cells.
    Now is the time to introduce new foods, new vegetables, new fruits, new recipes, and new dishes altogether.

    The liver and immune system become overactive, overwhelmed,
    and confused, and allergies as well as addictions may develop
    as a result. One should try to get rid of stress and
    anxieties as they are also known to cause memory loss. For
    more about supplementing for optimal health read Five supplements every adult should take,
    which includes vitamin d and fish oil. In severe
    cases, B12 injections are necessary to prevent further
    development of anemia and improve the central nervous system.

    In my opinion, Vitamin Code Raw D3 stands out above the other Vitamin D3
    dietary supplements because it contains 2,000 IU of Vitamin D3,
    is the only raw, vegetarian, whole food vitamin D complex that is formulated with raw food-created nutrients and cultivated with live probiotics, antioxidants,
    enzymes and nutrient-specific peptides for maximum delivery and absorption.
    There are different ways to improve poor memory like stress reduction, physical fitness and diet for poor memory.

    The B vitamin Choline is necessary for: gallbladder regulation; brain and memory
    function; liver function; mental clarity and mental function; hormone production; cholesterol metabolism;
    and fat metabolism; proper transmission of nerve impulses; and even
    Parkinson’s Disease and tardive dyskinesia. All you have to do is be aware that
    alcohol is quite bad for your life. It’s not surprising – the supplement is a combination of more than 30 natural ingredients, each carefully incorporated to work well with others in targeting the different causes
    of memory loss. Without it working at a one hundred
    percent rate, there could be potential future problems for it in the
    future. Sometimes all you need is a bit more time
    to allow your memory to retrieve the information.

  25. You should do your very best to eat a very well-balanced diet daily.
    There are many new and innovative natural methods for stretch mark
    removal that can be tried. Deep tissue massages
    can also help reduce the appearance of cellulite.

  26. hello there! , Is fantastic publishing really a good deal! percentage all of us maintain your correspondence excess about your article for America online? I demand a expert during this dwelling to be able to unravel our difficulty. Possibly that is certainly a person! Looking ahead to search people.

  27. Nathan says:

    I see a lot of interesting articles on your page.
    You have to spend a lot of time writing, i know how to save you a lot of time, there
    is a tool that creates unique, google friendly posts in couple of minutes, just search in google – k2 unlimited content

Leave a Reply