Strong, Weak, Soft and Phantom References

Naveen AnamaneniUpdated · 5 min read

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

ReferenceCreated withCleared whenget() returnsTypical use
StrongStudent s = new Student()Never, while reachableThe objectEveryday code
Softnew SoftReference<>(obj)Only when the JVM is low on memoryThe object, or null once clearedMemory-sensitive caches
Weaknew WeakReference<>(obj)At the next GC, if no strong or soft references remainThe object, or null once clearedWeakHashMap, listeners, metadata
Phantomnew PhantomReference<>(obj, queue)After the object is finalized and about to be reclaimedAlways nullCleanup after collection (Cleaner)

Example: Weak and Soft References

Let's see an example that drops the strong references and runs a garbage collection.

References.java▶ Try it
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)");
    }
}
Output
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.

CleanerDemo.java▶ Try it
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));
    }
}
Output
Released native memory for Advitha
Cleanup ran? true

Explanation: 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

  1. Easy: Show that a WeakReference to a String created with new String("Navika") is cleared after the strong reference is dropped and a GC runs.
  2. Harder: Build a tiny image cache with SoftReference values in a HashMap, fill the heap with other data under -Xmx64m, and show that the cached images are cleared before an OutOfMemoryError.

Quick check: Reference types

4 questions
1When is a soft reference cleared?
2When is a weak reference cleared?
3What does PhantomReference.get() return?
4What replaced finalize() for cleanup?

Key Takeaways

Was this tutorial helpful?

Lesson 446 of 482