I’ve often read developer forums where Java WeakReference and SoftReference are touted as the ultimate answer to preventing memory leaks.
They can never take the place of good programming practices, such as declaring variables in the correct scope, releasing references when no longer needed, and using the close() methods of objects to release resources. However, if fully understood and implemented correctly, they can be a useful addition to our memory management strategy. The downside is that if they’re not used as intended, they can cause more problems than they solve.
In this article, we’ll look at what WeakReferences and SoftReferences actually do, how to define them, and when they can be used with advantage.
Java Memory Leaks
A memory leak is a situation where a program uses more and more unnecessary memory as time goes on. After a while, performance is degraded, and eventually, the application is likely to crash with an OutOfMemoryError.
You may like to read this article, which describes Common Memory Leaks and How to Fix Them.
Not all memory issues are caused by leaks. In some cases, the application is simply wasting memory. In others, the system is under-configured, and the JVM parameters need to be adjusted.
The easiest way to check if an application has a memory leak is to activate garbage collection logging, and use a log analyzer tool such as GCeasy to obtain GC analytics. The image below was taken from a GCeasy report on a program that has a memory leak. The graph shows memory usage over time, with full GC events shown as red triangles. Notice how each successive GC cycle is clearing less memory, until the GC is running almost continuously.

Fig: GCeasy Report Showing a Memory Leak Pattern
For a demonstration on how to use a heap dump analyzer such as HeapHero to diagnose memory leaks, watch How to Analyze a Heap Dump Fast.
Java WeakReferences and SoftReferences: What Are They?
Think of it this way. You’re moving to a smaller house and have to get rid of anything you don’t need, or you won’t be able to fit everything in. You go through all the clothes, and put them in four piles. Pile A are things you definitely need. Pile B are things you’d like to keep, but only if there’s room for them. Pile C are children’s clothes, but you’re not sure if they still fit any of the kids. If they do, you’ll keep them. Pile D are things you will definitely throw away.
In Java, strong references are things you definitely need to keep. Soft references are things you’d like to keep if there’s room, and weak references are things you only want to keep if someone else needs them.
Unless otherwise specified, all references in Java are strong references. This means that they can’t be garbage collected while the reference is still valid (i.e. still within scope and not explicitly set to null.)
Other types of reference are explicitly defined as one of the subclasses of the abstract class java.lang.ref.Reference. It has three subclasses: WeakReference, SoftReference and PhantomReference.
Weak references are very simple. If nothing in the program is holding a strong reference to the variable, and it’s defined via a WeakReference, it will be garbage collected on the next GC cycle.
If we wanted to hold a weak reference to String object named myString, we’d define the reference like this:
Weakreference<String> stringRef = new Weakreference(myString);
To retrieve the object pointed to by stringRef, we’d use the get() method of the WeakReference class.
String referredString=stringRef.get();
if (referredString != null) {
// GC hasn't removed the instance yet
// We can use the string
} else {
// GC has cleared the instance
// We can’t use it
}
Since we can never be sure whether the weak reference has been garbage collected, we always need to check whether the get() method returns null, otherwise the program is likely to crash with a NullPointerException
At this point in the program, provided the get() method didn’t return null, referredString is holding a strong reference to the object, and it won’t be garbage collected. If referredString goes out of scope or is set to null, the object will be garbage collected even though stringRef holds a weak reference to it.
Soft references are a little more complex. We’d use the SoftReference class to define them and retrieve them, using similar syntax to the WeakReference class. Soft references can also be garbage collected if no strong references point to the same object, but this will only happen if the JVM is encountering memory issues.
It’s important to be aware that different implementations of the JVM may behave slightly differently regarding garbage collecting soft references. The JVM specification simply states that all soft references must have been garbage collected before the system throws an OutOfMemoryError.
The Java Hotspot JVM has a very practical implementation, in that it uses an algorithm which checks the time the object was last used before it decides whether or not to garbage collect it. By default, it drops softly-referenced objects if they haven’t been used for 1000 milliseconds per megabyte of free heap. Therefore, if there is 50 MB free on the heap, softly referenced objects will be kept for 50 seconds.
This default can be overridden using a JVM command line argument. To run the program MyProg, keeping soft references for 500 ms per MB free space, the JVM command is:
java -XX:SoftRefLRUPolicyMSPerMB=500 MyProg
Different GC algorithms may behave slightly differently regarding soft references. Older algorithms such as Serial and Parallel only collect soft references during a full GC event. This can sometimes lead to long pause times during full GC if there are a lot of soft references to be collected.
These differences must be borne in mind if your application is likely to be used on several different platforms. If you’re using soft references extensively, it’s a good idea to monitor the GC logs regularly, and analyze them to make sure key performance indicators such as latency and throughput continue to be acceptable.

Fig: Key Performance Indicators Extracted by GCeasy
The third type of reference, PhantomReference, is beyond the scope of this article, but it’s worth briefly mentioning that, in conjunction with a ReferenceQueue object, it can be used to carry out clean-up operations before an object is garbage collected. This is a safer alternative than the finalize() method, which is deprecated in later versions of Java.
When Would We Use WeakReference?
Weak references are particularly useful if we want to cache large objects, such as images or long strings, as auxiliary data belonging to some other item. A web browser, for example, may want to cache images for web pages that the user is working with, but should release them when the tab is closed. As another example, when a customer is logged in, we may want to keep his details in memory: perhaps the name, the address and a list of recent transactions. When the customer logs out, we’d want to drop all this auxiliary data because it’s no longer needed. We could, of course, include code that clears all this data, but it’s much too easy to forget to clear something.
The class WeakHashMap works in the same way as a HashMap, except the keys are held as weak references. If the key is no longer held by a strong reference elsewhere, the whole entry is garbage collected.
Weak references are not suitable for caching solutions such as holding recently-used data from a database. They would defeat the object of holding the cache, since cached items are likely to be garbage collected almost immediately.
Another good use of weak references is when writing a class that will be used as an event source. These classes allow other objects to register themselves as listeners for related events. A memory leak can occur if listeners are not deregistered when they go out of scope or are set to null. Because the event source holds a strong reference to the listener, the listener can’t be garbage collected. It’s good practice when writing an event source, therefore, to store the listeners as weak references.
They are sometimes used in canonical mapping to prevent duplicates.
When Would we Use Soft References
Soft references can be used as a precaution against OutOfMemoryErrors when using caches. It’s not as good a solution as setting sensible limits and implementing a clearance policy on the cache, but it can prevent system crashes.
A good usage for it would be in processing large objects such as images, video and audio, where the user may want to go back and work on a previous clip. If there’s plenty of memory, it will facilitate fast processing, but if memory runs short, it will release the least-recently used objects.
What Issues Do We Need to Guard Against When Using Weak and Soft References?
When using soft references, it’s important to monitor key performance indicators from the GC logs to make sure they’re running as expected. Since they work slightly differently with different JVMs and GC algorithms, we may need to do some tuning to get the system to work as it should.
If we’re using them in a cache, it’s a good idea, if possible, to monitor the cache hit rate to make sure this hasn’t dropped to unacceptable levels.
It’s important to always check for null pointers when dealing with weak and soft references, since the object may be garbage collected at any time.
Lastly, we need to be aware that neither weak nor soft references will prevent memory issues caused by slow finalize() methods. If these methods have to wait for any considerable time for resources, it can cause a memory leak, even though weak or soft references were used. The finalize() method is now deprecated.
Conclusion
Although weak and soft references do have their uses in preventing certain types of memory leak, they’re not the answer to all memory issues.
We should ensure that they’re tested thoroughly, and put good performance monitoring in place when they’re introduced into production. Regular garbage collection log analysis with a tool such as GCeasy lets us ensure that key performance indicators are always kept at an acceptable level.

Share your Thoughts!