ImageView / WeakReference

Memory Cache – Part 1

Previously on Styling Android we have discussed how important it is to make your app as fast as possible because making your user wait for things to happen is a sure way to drive them away from your app. Also, you have to be quite careful when it comes to using images within your app because images tend to be relatively large and even minor inefficiencies in image handling can have a major impact on your app. In this series of articles we’re going to look at a technique of using a memory cache for images to avoid having to hold multiple copies of the same image in memory when that image is used multiple times in your layout.

Before we begin, let’s have a quick reminder about how Android and Java memory management works. Strictly speaking the JVM does not necessarily use reference counts for each object as described below, however this is a useful metaphor to help understand how Garbage Collection works, so we’ll use it for the sake of clarity.

The following code does a number of things:

[java] String string = new String();
[/java]

Firstly the new keyword allocates the memory for, initialises and calls the constructor on a new String object. The second thing that it does is create a reference to that new String object which is assigned to the variable named string. When this reference is made, a reference count on the String object is incremented. When the string variable goes out of scope (i.e. it’s a local variable in a method, and we return from the method), or is changed to reference a different object, or is nulled, then the reference is to the String object destroyed and the reference count on the String object is decremented. We can also create new references to the same object:

[java] String newRef = string;
[/java]

This will cause the reference count on the String object to be incremented again.

The Java VM has a garbage collector which runs periodically (and specifically when memory is getting low). The garbage collector looks for objects which have a reference count of 0 (i.e. all of the references to that object have gone out of scope) and it destroys these objects thus freeing up the memory that they are using. This is known as the object being garbage collected (or GC’d).

When we create these references to the String object, they are “strong” references which means that the existence of one or more strong references to a given object is enough to prevent that object from being GC’d. There is another kind of reference, a weak reference, which still permits us access to an object, but the existence of the weak reference will not prevent the object that it references from being GC’d. I am not going to give a detailed introduction to weak references, but if you want to know more then there is an excellent description of them here. There are also other kinds of reference which are subtly different from weak references (soft & phantom references) which are beyond the scope of our discussion.

Now that we know what a weak reference is how do we go about creating one? The answer is using the java.lang.ref.WeakReference class. This is a generic class which takes the class of the object that we want to create a reference to as its generic type:

[java] String string = new String();
WeakReference wr = new WeakReference( string);
[/java]

We now hold both a strong reference (though our string variable) and a weak reference (through our wr variable) to the String object. We can access the object itself via the weak reference by calling its get() method:

[java] String newRef = wr.get();
[/java]

This will effectively create another strong reference to the String object.

On the face of it, weak references sound rather dangerous. What happens if I try and access the referenced object after it has been GC’d? Well it’s actually not that bad. The get() method of wr will simply return null. As long as we properly handle a null then everything is fine.

Now that we understand a bit about weak references, we can look at building an in-memory image cache which will allow us to re-use bitmaps that have already been loaded in to memory which saves both image loading time, and reduces memory consumption. In the next part of this series we’ll start putting this knowledge in to practice.

© 2012, Mark Allison. All rights reserved.

Copyright © 2012 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.

8 Comments

  1. Don’t forget android.util.LruCache! It’s the best way to do memory caching on Android. It’s preferred over SoftReferences because it’s far more predictable.

  2. Interesting article. Unfortunately, it contains several mistakes that I’d like to fix :

    – First you said “The garbage collector looks for objects which have a reference count of 0”. This is not true. Let’s say you have A referencing B and B referencing A. Then A and B both have a reference count of 1. Nevertheless, if those two objects are found “as it” in memory they will be garbaged. Most garbage collectors are not implementing using a reference counting algorithm but rather a traversing algorithme. The true behavior is the garbage collector follows references starting from GC roots. When all references has been followed all objects that has not been traversed are garbaged. [Edit] I missed the line where you explained reference counting was a way to make things more understandable. Sorry 🙂 I will let this here so that people can understand the actual GC behavior.

    – WeakReferences are definitely not appropriate for caches. I’m not sure you’ll use it in the second part of this article but if you do, you’ll have a pretty crappy cache. Those references may be cleared as soon as is known to be weakly-referenced by the garbage collector . I don’t consider this as an appropriate way to implement a cache 🙂 SoftReferences are more appropriate but they’re quite unpredictable (as Jesse said). Using the LRU efficiently is probably a better solution…

    1. I will be covering quite a specific use-case in the next part of the article. It is a short-lived caching model which is not designed to survive an Activity transition. It is designed to cache when memory is plentiful but readily free up reasources when memory becomes tight. For this reason, WeakReferences work perfectly well. Hopefully things will become clearer when you read part 2…

      Also, I will be covering LruCache later in the series.

  3. I also need to re-write all the code of an Image Manager that I found on internet.

    It was prety ugly-written 😀
    At the moment I’m not using WeakReference for my image manager that is strongly used in a list view to display, for each row, an image.

    At the moment I’m using your Endless adapter with that ImageManager.
    I noticed that with the WeakReferences images are dumped too many times so it creates lags on scrolling and too many refreshing on images of the list view (that will load the default image when there’s no one in the cache of the image manager).

    So at the moment I’m using Softreferences that last until the end (when the app is really in trouble and is near the insufficient memory state).

    When I will rewrite it I will post the source code of it 🙂

  4. Sir Your Blog one of the best i have read but sir please can you add a search bar for finding required topic.

    1. Many thanks for the feedback. You may notice that there is now a search option in the right hand column.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.