Fundamentals 9 min read

Mastering Java’s Four Reference Types: Strong, Soft, Weak, and Phantom

Explore Java’s four reference types—strong, soft, weak, and phantom—understanding their behavior, garbage collection interactions, practical code examples, and best-use scenarios, while learning how to manage memory efficiently and avoid pitfalls such as improper finalize() overrides.

Xuanwu Backend Tech Stack
Xuanwu Backend Tech Stack
Xuanwu Backend Tech Stack
Mastering Java’s Four Reference Types: Strong, Soft, Weak, and Phantom

Java’s Four Reference Types

Java defines four reference types: strong, soft, weak, and phantom.

1. Strong Reference

Strong references are the default; objects with strong references are not reclaimed unless the reference is cleared (e.g., set to null). Object obj = new Object(); Example with Order class overriding finalize() to show when GC occurs:

/** 订单对象 */
public class Order {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("order对象被垃圾回收");
    }
}

Test class:

public class NormalReferenceTest {
    public static void main(String[] args) throws IOException {
        Order order = new Order();
        // break reference
        order = null;
        // request GC
        System.gc();
        System.out.println(order);
        // block main thread
        System.in.read();
    }
}

Output shows the Order object is reclaimed.

2. Soft Reference

SoftReference wraps an object and can be retrieved with get(). It is cleared only when the JVM needs memory.

SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 10]); // 10 MB
softReference.get(); // retrieve

Demo steps: set -Xmx20M, create a 10 MB soft reference, call get(), trigger GC, allocate additional 12 MB array, observe that the soft reference becomes null after memory pressure.

public class SoftReferenceTest {
    public static void main(String[] args) throws InterruptedException {
        SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 10]); // 10M
        System.out.println(softReference.get());
        System.gc();
        Thread.sleep(200);
        System.out.println(softReference.get());
        byte[] bytes = new byte[1024 * 1024 * 12]; // 12M, forces GC
        System.out.println(softReference.get());
    }
}

Result: first two prints show a non‑null value, the third prints null, demonstrating that soft references are cleared under memory shortage, making them suitable for caches.

3. Weak Reference

WeakReference also wraps an object but is reclaimed on any GC cycle, regardless of memory availability.

WeakReference<Order> weakReference = new WeakReference<>(new Order());
System.out.println(weakReference.get()); // non‑null
System.gc();
Thread.sleep(200);
System.out.println(weakReference.get()); // null

Weak references are used in structures like WeakHashMap and ThreadLocal.

4. Phantom Reference

PhantomReference cannot retrieve the referent (get() always returns null) and is used together with a ReferenceQueue to perform cleanup actions after an object is reclaimed.

ReferenceQueue<Order> queue = new ReferenceQueue<>();
PhantomReference<Order> phantom = new PhantomReference<>(new Order(), queue);
System.out.println(phantom.get()); // null

In a typical usage, a background thread polls the queue to detect when the phantom‑referenced object has been collected.

public class PhantomReferenceTest {
    public static void main(String[] args) {
        List<Object> list = new ArrayList<>();
        ReferenceQueue<Order> queue = new ReferenceQueue<>();
        PhantomReference<Order> phantom = new PhantomReference<>(new Order(), queue);
        new Thread(() -> {
            while (true) {
                list.add(new byte[1024 * 1024]); // fill memory
                System.out.println(phantom.get());
            }
        }).start();
        new Thread(() -> {
            while (true) {
                Reference<? extends Order> ref = queue.poll();
                if (ref != null) {
                    System.out.println("Phantom reference object reclaimed: " + ref);
                }
            }
        }).start();
    }
}

When the heap is exhausted, the phantom reference is enqueued, allowing the program to react before the object’s memory is reclaimed.

Note: Overriding finalize() in production code is discouraged because it can degrade GC performance and lead to memory leaks.

Javamemory managementGarbage CollectionWeakReferenceReference TypesPhantomReferenceSoftReference
Xuanwu Backend Tech Stack
Written by

Xuanwu Backend Tech Stack

Primarily covers fundamental Java concepts, mainstream frameworks, deep dives into underlying principles, and JVM internals.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.