Question

SoftReference vs WeakReference in Java

javareferenceweak-referencessoft-references

Question

What is the difference between java.lang.ref.WeakReference and java.lang.ref.SoftReference in Java? In particular, how does the garbage collector treat each type of reference, and when should each one be used?

Short Answer

Java provides WeakReference and SoftReference for cases where an object should not be kept alive by a normal strong reference. A weakly referenced object is usually collected as soon as it becomes otherwise unreachable. A softly referenced object may remain available longer, but the JVM can clear it when memory is needed. By the end, you will know their garbage-collection behavior, limitations, and appropriate use cases.

Concept

A normal Java variable holds a strong reference:

User user = new User();

As long as user is reachable, the garbage collector (GC) must keep the User object in memory.

The classes in java.lang.ref let you hold references that do not necessarily keep an object alive:

  • WeakReference<T> holds a weak reference.
  • SoftReference<T> holds a soft reference.

When an object is reachable only through a WeakReference, it is weakly reachable. The GC can clear that reference during a collection cycle. In practice, you should assume a weakly referenced object can disappear at any time after its last strong reference is gone.

When an object is reachable only through a SoftReference, it is softly reachable. The JVM may keep it around for a while, but it can clear the reference when it needs memory. The Java specification does not promise exactly when this happens.

This matters because get() can return either the referenced object or null:

T value = reference.get();

A null result means the reference has been cleared, so your program must handle it safely.

Neither reference type is a replacement for normal ownership or lifecycle management. They are specialized tools for optional, recreatable data and for avoiding accidental retention of objects.

Mental Model

Think of memory as a storage room and the garbage collector as the person deciding what can be removed.

  • A strong reference is like a signed ownership document: the item must stay.
  • A soft reference is like a note saying: “Keep this item if there is space; throw it away if storage is needed.”
  • A weak reference is like a temporary pointer on a whiteboard: once no one officially owns the item, the cleaner can erase both the item and the pointer.

The important rule is that a soft or weak reference is not a promise that an object will still exist when you ask for it. Always check the result of get().

Take Quiz

Syntax and Examples

Create soft and weak references with their generic type:

import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

public class ReferenceExample {
    public static void main(String[] args) {
        String strongValue = new String("report data");

        SoftReference<String> softRef = new SoftReference<>(strongValue);
        WeakReference<String> weakRef = new WeakReference<>(strongValue);

        System.out.println(softRef.get()); // report data
        System.out.println(weakRef.get()); // report data

        strongValue = null;

        // The objects may still be available now, but GC may clear them later.
        String fromSoftReference = softRef.get();
        String fromWeakReference = weakRef.get();

        if (fromSoftReference != null) {
            System.out.println("Soft value is still available");
        }

        if (fromWeakReference != null) {
            System.out.println("Weak value is still available");
        }
    }
}

softRef.get() and weakRef.get() return the object while it remains available. After the final strong reference is removed, neither result is guaranteed:

  • The weak reference is eligible to be cleared during GC.
  • The soft reference may remain until the JVM decides to reclaim memory.

Do not write code that assumes a particular call to System.gc() will clear either reference. System.gc() is only a request to the JVM, not a guarantee.

Step by Step Execution

Consider this example:

import java.lang.ref.WeakReference;

public class WeakTrace {
    public static void main(String[] args) {
        String message = new String("temporary");
        WeakReference<String> ref = new WeakReference<>(message);

        message = null;

        String value = ref.get();
        System.out.println(value);
    }
}

Step by step:

  1. new String("temporary") creates a String object.
  2. message is a strong reference to that object.
  3. ref is a weak reference to the same object.
  4. message = null removes the strong reference held by message.
  5. The object is now reachable only through ref, so it is eligible for weak-reference processing during GC.
  6. If GC has not cleared ref yet, ref.get() returns "temporary".
  7. If GC has cleared it, ref.get() returns null.

The output is therefore not guaranteed to be the same on every run. It may print temporary or null depending on whether garbage collection happened and cleared the reference before get() ran.

Real World Use Cases

WeakReference use cases

  • Listener registries: A publisher can avoid keeping a listener alive forever when the rest of the application has stopped using it.
  • Metadata associated with external objects: Store optional data without making the external object remain in memory solely because of that metadata.
  • Canonical mappings: WeakHashMap uses weak keys, which can be useful when entries should vanish after their keys are no longer used elsewhere.

SoftReference use cases

  • Recreatable, memory-sensitive values: For example, an expensive derived value that can be calculated again if it was cleared.
  • Legacy cache-like behavior: Soft references have historically been used for caches, although they are often not ideal for modern application caches because eviction timing is controlled by the JVM and is unpredictable.

For an application cache with predictable limits, expiration, statistics, and eviction rules, use a dedicated cache library or an explicit bounded-cache design instead of relying on SoftReference.

Take Quiz

Real Codebase Usage

In production code, weak references are commonly used to avoid accidental memory retention.

Check for null immediately

A reference can be cleared before you use it, so retrieve it once and check it:

UserProfile profile = profileReference.get();
if (profile == null) {
    profile = loadProfile();
    profileReference = new SoftReference<>(profile);
}

return profile;

Storing get() in a local variable gives the method a strong reference to the object while that local variable remains reachable.

Use WeakHashMap for weak keys

Instead of manually managing weak keys, use WeakHashMap when its semantics fit:

import java.util.Map;
import java.util.WeakHashMap;

Map<Object, String> labels = new WeakHashMap<>();

Object component = new Object();
labels.put(component, "sidebar");

component = null;
// After garbage collection, the entry may be removed.

Its entries are not stable storage. A key can disappear when no strong reference to that key exists elsewhere.

Use ReferenceQueue when cleanup matters

If you need to be notified that references were cleared, create a ReferenceQueue. A background cleanup task can remove associated bookkeeping data when references are enqueued. This is useful for specialized registries, but it adds concurrency and lifecycle concerns.

Prefer explicit cache policies

For most caches, developers use explicit policies such as maximum size, time-to-live, invalidation, and metrics. These policies are easier to test than JVM-controlled soft-reference eviction.

Common Mistakes

Assuming get() never returns null

Broken code:

WeakReference<String> ref = new WeakReference<>(new String("data"));
System.out.println(ref.get().length());

If the weak reference has been cleared, this throws NullPointerException.

Use a local variable and validate it:

String value = ref.get();
if (value != null) {
    System.out.println(value.length());
}

Expecting System.gc() to produce a reliable result

Broken test idea:

System.gc();
assert ref.get() == null;

The JVM is not required to run GC immediately, or to clear a particular reference at that exact point. Do not build application logic or deterministic tests around it.

Keeping an accidental strong reference

Object object = new Object();
WeakReference<Object> ref = new WeakReference<>(object);

// `object` still strongly references the instance here.

The object cannot become weakly reachable until all relevant strong references are gone. This can include fields, collections, local variables, callbacks, and static variables.

Using soft references as a predictable cache limit

A SoftReference does not mean “keep exactly 100 items” or “remove items after five minutes.” JVM memory pressure determines when values may be removed. Use an explicit cache if predictable behavior matters.

Using weak references for required data

Do not place essential application state only behind a WeakReference. The data may vanish while the application still needs it. Weak references are appropriate only when losing the object is acceptable.

Comparisons

Reference typeKeeps object alive?When can it be cleared?Typical purpose
Strong referenceYesOnly when no strong references remainNormal program state
SoftReferenceNot permanentlyAt JVM discretion, commonly under memory pressureOptional, recreatable values
WeakReferenceNoWhen the object is otherwise unreachable and GC processes weak referencesAvoiding unintended retention
PhantomReferenceNoAfter finalization-related reachability processing; accessed through a queueAdvanced resource cleanup tracking

WeakReference vs SoftReference

  • Choose weak when the referenced object should not stay alive because of your reference.
  • Choose soft only when retaining a recreatable object opportunistically is acceptable and unpredictable eviction is acceptable.
  • Both require null handling after get().

WeakReference vs WeakHashMap

  • WeakReference<T> gives direct control over one weakly held object.
  • WeakHashMap<K, V> holds its keys weakly and removes entries when keys become unreachable elsewhere. Its values may still indirectly keep keys alive, so avoid value-to-key reference paths when you expect entries to disappear.
Take Quiz

Cheat Sheet

import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

SoftReference<Data> softRef = new SoftReference<>(data);
WeakReference<Data> weakRef = new WeakReference<>(data);

Data value = weakRef.get(); // Data or null
  • Strong references keep objects alive.
  • WeakReference does not keep its referent alive.
  • SoftReference may retain its referent until the JVM needs memory.
  • get() can return null; always handle that case.
  • Do not rely on System.gc() for correctness or tests.
  • Remove all unintended strong references before expecting collection.
  • Use weak references for optional associations and listener-like registries.
  • Prefer explicit bounded or expiring caches over soft-reference caches when eviction must be predictable.
  • Use ReferenceQueue only when you need cleanup notification after references are cleared.

FAQ

Is SoftReference stronger than WeakReference?

Yes. A softly reachable object is generally retained longer than a weakly reachable object, but neither is guaranteed to remain available.

When does Java clear a WeakReference?

After its referent is no longer strongly or softly reachable and the garbage collector processes weak references. The exact timing is not guaranteed.

When does Java clear a SoftReference?

The JVM decides. Soft references are commonly cleared in response to memory demand, but application code must not depend on a specific collection time.

Can WeakReference.get() return null immediately?

Yes. If there is no other strong reference to the object, GC may clear the weak reference before your next call to get().

Should I use SoftReference to implement a cache?

Usually not when the cache needs reliable behavior. Soft-reference eviction is JVM-controlled and difficult to predict. Prefer a cache with explicit size, expiration, and invalidation policies.

Does calling System.gc() guarantee that a weak or soft reference is cleared?

No. It is a request, not a guarantee, and the timing and outcome are JVM-dependent.

What is WeakHashMap used for?

It stores map keys weakly. An entry can be removed when its key is no longer strongly referenced elsewhere, which is useful for optional metadata associated with objects.

Take Quiz

Mini Project

Description

Build a small document-preview store that holds expensive-to-create previews with SoftReference. A preview may remain available for a later request, but the application can regenerate it when the JVM has cleared it. This demonstrates the essential rule for soft references: treat the value as optional and recover when get() returns null.

Goal

Create a preview store that returns a cached preview when available and regenerates it when it is missing or has been cleared.

Requirements

Use a Map<String, SoftReference<String>> to store previews by document ID.

Take Quiz

Keep learning

Related questions

View more