Strong, soft, weak and phantom
Four ways to hold an object, from never collected to a signal that it has already gone.
Open this lesson in the learning hubKey points
- An ordinary field is a strong reference. While one is reachable from a GC root the object simply cannot be collected.
- A
SoftReferenceis cleared only when memory is running short. The VM must clear every one before it throws an OOME. - A
WeakReferenceis cleared at the next collection that finds nothing else pointing at the object. - A
PhantomReferencenever hands the object back. It exists purely to tell you the object has gone. - A
ReferenceQueuereports which references were cleared. That is howWeakHashMapandCleanertidy. - Use
Cleaner, neverfinalize(). Finalizers are deprecated for removal and can resurrect the object they clean.
Example
import java.lang.ref.Cleaner;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
public class Main {
public static void main(String[] args) throws InterruptedException {
ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
byte[] strong = new byte[1024];
WeakReference<byte[]> weak = new WeakReference<>(strong, queue);
SoftReference<byte[]> soft = new SoftReference<>(new byte[1024]);
System.out.println("while a strong reference exists : weak=" + state(weak.get())
+ " soft=" + state(soft.get()));
strong = null; // the only strong reference is gone
for (int i = 0; i < 10 && weak.get() != null; i++) { System.gc(); Thread.sleep(20); }
Reference<?> dead = null;
for (int i = 0; i < 20 && dead == null; i++) { dead = queue.poll(); Thread.sleep(10); }
System.out.println("after dropping it and running a few collections:");
System.out.println(" weak -> " + state(weak.get()) + " cleared: nothing else pointed at it");
System.out.println(" soft -> " + state(soft.get()) + " kept: the heap is nowhere near full");
System.out.println(" the cleared weak reference was enqueued: " + (dead != null));
System.out.println();
Cleaner cleaner = Cleaner.create(); // runs on its own daemon thread
Object handle = new Object();
cleaner.register(handle, () ->
System.out.println(" cleaner ran - this is where you release a native handle"));
handle = null;
System.out.println("Cleaner is the replacement for finalize():");
for (int i = 0; i < 20; i++) { System.gc(); Thread.sleep(20); }
System.out.println(" (the action never sees the object, so it cannot resurrect it)");
}
static String state(Object o) { return o == null ? "collected" : "alive "; }
}
Strong keeps it, soft caches it, weak forgets it, phantom just tells you.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the JVM course, and every lesson in it is listed on the JVM contents page.