104. Reference Types: Strong, Soft, Weak, and Phantom
Java provides four reference strengths (Strong, Soft, Weak, Phantom) allowing developers to cooperate with the garbage collector for caches, canonical mappings, and resource cleanup.
Java 21 (java.lang.ref package)Explanation
Every standard variable assignment (Object obj = new Object()) creates a Strong Reference. As long as an object is reachable via any chain of strong references, the garbage collector will never reclaim it, throwing OutOfMemoryError instead if memory is exhausted.
To build memory-sensitive caches and resource managers, java.lang.ref provides three weaker reference types: 1. SoftReference (SoftReference<T>): The JVM reclaims softly referenced objects only when memory is low (before throwing OutOfMemoryError). Ideal for in-memory caches where dropping cached data is preferable to crashing. 2. WeakReference (WeakReference<T>): Reclaimed eagerly during the very next garbage collection cycle once no strong or soft references exist. Canonical use: java.util.WeakHashMap, where keys are weakly referenced so map entries don't leak memory when keys are discarded elsewhere. 3. PhantomReference (PhantomReference<T>): Enqueued on a ReferenceQueue only after the object has been completely finalized and memory is ready to be reclaimed. Unlike finalize() (now deprecated), phantom references cannot resurrect objects. Modern Java uses java.lang.ref.Cleaner (built on phantom references) for safe native resource deallocation.
Example
import java.lang.ref.Cleaner;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
public class ReferenceTypesDemo {
// Modern cleanup using java.lang.ref.Cleaner (replaces deprecated finalize)
private static final Cleaner CLEANER = Cleaner.create();
static class NativeResource implements AutoCloseable {
private final Cleaner.Cleanable cleanable;
NativeResource() {
// Register resource cleanup action (run if object is garbage collected)
this.cleanable = CLEANER.register(this, () -> {
System.out.println("Cleaned up native handle safely via PhantomReference!");
});
}
@Override
public void close() { cleanable.clean(); }
}
public static void main(String[] args) {
// 1. Soft Reference (GC reclaims under memory pressure)
byte[] cacheData = new byte[1024 * 1024];
SoftReference<byte[]> softRef = new SoftReference<>(cacheData);
cacheData = null; // now only softly reachable
System.out.println("Soft reference value present: " + (softRef.get() != null));
// 2. Weak Reference (GC reclaims on next cycle)
String tempKey = new String("ephemeral-key");
WeakReference<String> weakRef = new WeakReference<>(tempKey);
tempKey = null; // now only weakly reachable
System.gc(); // Hint to JVM
System.out.println("Weak reference after GC: " + weakRef.get()); // null
// 3. Cleaner test
new NativeResource(); // Dropped immediately
System.gc();
}
}Sources
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/ref/package-summary.html โ java.lang.ref Package Summary
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/ref/Cleaner.html โ java.lang.ref.Cleaner API