Strong, Weak, Soft and Phantom References
Most references in Java are strong: as long as one exists, the object stays alive. The java.lang.ref package adds three weaker kinds that let the garbage collector reclaim an object even while you still have a reference to it. A soft reference is cleared only when memory runs low, which suits caches. A weak reference is cleared at the next collection once no strong references remain, which suits metadata attached to other objects. A phantom reference never gives the object back; it only tells you after the object has been collected, which suits cleanup. In this lesson, you will learn all four with examples.
The Four Reference Strengths
| Reference | Created with | Cleared when | get() returns | Typical use |
|---|---|---|---|---|
| Strong | Student s = new Student() | Never, while reachable | The object | Everyday code |
| Soft | new SoftReference<>(obj) | Only when the JVM is low on memory | The object, or null once cleared | Memory-sensitive caches |
| Weak | new WeakReference<>(obj) | At the next GC, if no strong or soft references remain | The object, or null once cleared | WeakHashMap, listeners, metadata |
| Phantom | new PhantomReference<>(obj, queue) | After the object is finalized and about to be reclaimed | Always null | Cleanup after collection (Cleaner) |
Example: Weak and Soft References
Let's see an example that drops the strong references and runs a garbage collection.
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
public class References {
public static void main(String[] args) throws InterruptedException {
byte[] photo = new byte[1_000_000];
byte[] report = new byte[1_000_000];
WeakReference<byte[]> weak = new WeakReference<>(photo);
SoftReference<byte[]> soft = new SoftReference<>(report);
System.gc();
System.out.println("With strong refs: weak alive? "
+ (weak.get() != null)
+ ", soft alive? " + (soft.get() != null));
photo = null;
report = null;
System.gc();
Thread.sleep(100);
System.out.println("After dropping strong refs:");
System.out.println(" weak cleared? " + (weak.get() == null));
System.out.println(" soft cleared? " + (soft.get() == null)
+ " (memory is not low)");
}
}With strong refs: weak alive? true, soft alive? true
After dropping strong refs:
weak cleared? true
soft cleared? false (memory is not low)Explanation: While photo and report hold strong references, neither array can be collected. After the strong references are dropped, the next GC clears the weak reference immediately. The soft reference survives because the heap has plenty of room; the JVM clears soft references only before it would otherwise throw OutOfMemoryError.
Example: Phantom References and Cleaner
java.lang.ref.Cleaner (Java 9) is the safe, modern way to use phantom references: it runs a cleanup action after an object becomes unreachable. It replaces the deprecated finalize() method.
import java.lang.ref.Cleaner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class CleanerDemo {
static final Cleaner CLEANER = Cleaner.create();
static class NativeBuffer {
NativeBuffer(String owner, CountDownLatch done) {
CLEANER.register(this, () -> {
System.out.println("Released native memory for " + owner);
done.countDown();
});
}
}
public static void main(String[] args) throws InterruptedException {
CountDownLatch done = new CountDownLatch(1);
NativeBuffer buffer = new NativeBuffer("Advitha", done);
buffer = null;
for (int i = 0; i < 10 && done.getCount() > 0; i++) {
System.gc();
done.await(100, TimeUnit.MILLISECONDS);
}
System.out.println("Cleanup ran? " + (done.getCount() == 0));
}
}Released native memory for Advitha
Cleanup ran? trueExplanation: CLEANER.register(this, action) attaches a phantom reference to the buffer. The cleanup action must not refer to the buffer itself, or the buffer would stay reachable forever; here it captures only the owner's name. After the buffer becomes unreachable and is collected, the cleaner's thread runs the action.
Common Mistakes
Using WeakReference as a cache. Entries vanish at the next GC; soft references or a real cache library suit caching better.
Letting a Cleaner action capture the object it cleans. The object can never be collected.
Expecting PhantomReference.get() to return the object. It always returns null.
Interview Corner
What is the difference between strong, soft, weak and phantom references?
A strong reference prevents garbage collection as long as it's reachable. A SoftReference's referent is cleared only when the JVM needs memory, before an OutOfMemoryError would be thrown, so it suits memory-sensitive caches. A WeakReference's referent is cleared at the next collection once only weak references remain, as used by WeakHashMap. A PhantomReference never returns its referent; it's enqueued in a ReferenceQueue after the object is determined unreachable, which enables post-mortem cleanup and underlies java.lang.ref.Cleaner.
Practice
- Easy: Show that a
WeakReferenceto aStringcreated withnew String("Navika")is cleared after the strong reference is dropped and a GC runs. - Harder: Build a tiny image cache with
SoftReferencevalues in aHashMap, fill the heap with other data under-Xmx64m, and show that the cached images are cleared before anOutOfMemoryError.
Key Takeaways
Was this tutorial helpful?