References

About

In Java, references determine how an object is accessed and managed in memory, especially with regard to garbage collection (GC). Java provides different types of references strong, weak, soft, and phantom each with varying implications on memory management.

1. Strong Reference

About

A strong reference is the default reference type in Java. It ensures that the referenced object remains in memory and is not eligible for garbage collection as long as the reference exists.

Characteristics

  • A strong reference prevents the garbage collector from reclaiming the memory of the referenced object.

  • The object will only be garbage collected if the reference is explicitly set to null or goes out of scope.

  • Most objects we create in Java are strong references by default.

Example of Strong Reference

public class StrongReferenceExample {
    public static void main(String[] args) {
        // The strongRef variable is a strong reference to the String object.
        String strongRef = new String("Hello, World!");
        
        // This object cannot be garbage collected until `strongRef` is set to null
        System.out.println(strongRef); // Output: Hello, World!
        
        // Nullify the reference
        strongRef = null;

        // Now the object is eligible for garbage collection
    }
}

When to Use

  • When we want to ensure the object is always accessible and not accidentally reclaimed by the garbage collector.

  • For most regular object references.

2. Weak Reference

About

A weak reference allows the garbage collector to reclaim the referenced object if there are no other strong references to it. Weak references are used when we want to allow the object to be garbage collected while still having a reference to it.

Characteristics

  • A weak reference does not prevent its referent (the object it refers to) from being garbage collected.

  • Used in conjunction with java.lang.ref.WeakReference class.

  • Often used for memory-sensitive caching and maps like WeakHashMap.

Example of Weak Reference

import java.lang.ref.WeakReference;

public class WeakReferenceExample {
    public static void main(String[] args) {
        // Create a strong reference
        String strongRef = new String("WeakReference Example");

        // Create a weak reference to the object
        WeakReference<String> weakRef = new WeakReference<>(strongRef);

        // Print the value via weak reference
        System.out.println("Before GC: " + weakRef.get()); // Output: WeakReference Example

        // Nullify the strong reference
        strongRef = null;

        // Request garbage collection
        System.gc();

        // Allow some time for GC to run
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Check if the object was garbage collected
        System.out.println("After GC: " + weakRef.get()); // Output: null (if GC collected the object)
    }
}

When to Use

  • Caches: Weak references are used in WeakHashMap to allow keys to be garbage collected when no longer in use.

  • Listeners: Weak references are used for listeners or observers in event-driven systems to avoid memory leaks.

What Happens in the Examples?

Strong Reference Example:

String strongRef = new String("Hello, World!");
  • The strongRef variable is a strong reference to the String object.

  • As long as strongRef exists and is not set to null, the garbage collector cannot reclaim the object, even if memory is low.

If we set strongRef = null, there are no references to the object, and it becomes eligible for garbage collection.

Weak Reference Example:

String strongRef = new String("WeakReference Example");
WeakReference<String> weakRef = new WeakReference<>(strongRef);
  • strongRef is a strong reference to the String object, and weakRef is a weak reference to the same object.

  • As long as strongRef exists, the object is not eligible for garbage collection, because the strong reference keeps it alive.

  • When we set strongRef = null, only the weak reference remains. This makes the object eligible for garbage collection, even if weakRef still points to it.

3. Soft Reference

About

A soft reference is a reference that allows the garbage collector to reclaim the referenced object only when the JVM runs out of memory. It is more lenient than a weak reference and is often used for implementing memory-sensitive caches.

Characteristics

  • The garbage collector clears a soft reference only when memory is low, making it useful for caching.

  • If a soft reference is not reclaimed, you can still access the object.

  • Implemented using the java.lang.ref.SoftReference class.

  • Provides a balance between strong and weak references: the object remains accessible unless the JVM is under memory pressure.

Example of Soft Reference

import java.lang.ref.SoftReference;

public class SoftReferenceExample {
    public static void main(String[] args) {
        // Create a strong reference
        String strongRef = new String("SoftReference Example");

        // Create a soft reference to the object
        SoftReference<String> softRef = new SoftReference<>(strongRef);

        // Print the value via soft reference
        System.out.println("Before GC: " + softRef.get()); // Output: SoftReference Example

        // Nullify the strong reference
        strongRef = null;

        // Request garbage collection
        System.gc();

        // Allow some time for GC to run
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Check if the object was garbage collected
        System.out.println("After GC: " + softRef.get()); // Likely still accessible unless memory is low
    }
}

When to Use:

  • Caching: Soft references are often used for memory-sensitive caching. For example, in an image cache: Images can be held in memory as long as the JVM has enough memory. If memory runs low, the cache will release them.

Phantom Reference

About

A phantom reference is the weakest type of reference in Java. Unlike weak or soft references, a phantom reference does not allow access to the referenced object at any point. Phantom references are typically used in conjunction with a ReferenceQueue to track the lifecycle of objects and perform cleanup operations after the object has been finalized but before its memory is reclaimed by the garbage collector.

Characteristics

  • Accessing the referent through PhantomReference.get() always returns null.

  • The primary use is for cleanup actions, as the reference is enqueued in a ReferenceQueue after the object is finalized but before memory is reclaimed.

  • Implemented using java.lang.ref.PhantomReference.

  • Requires a ReferenceQueue to be useful.

  • Used for advanced memory management tasks, such as ensuring certain cleanup tasks are performed before memory is freed.

Example of Phantom Reference

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;

public class PhantomReferenceExample {
    public static void main(String[] args) {
        // Create a strong reference
        String strongRef = new String("PhantomReference Example");

        // Create a reference queue
        ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();

        // Create a phantom reference to the object
        PhantomReference<String> phantomRef = new PhantomReference<>(strongRef, referenceQueue);

        System.out.println(phantomRef.get()); // Always returns null

        // Nullify the strong reference
        strongRef = null;

        // Request garbage collection
        System.gc();

        // Allow some time for GC to run
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Check if the object was enqueued
        Reference<? extends String> refFromQueue = referenceQueue.poll();
        if (refFromQueue != null) {
            System.out.println("The phantom-referenced object has been enqueued for cleanup.");
        } else {
            System.out.println("The object is not yet garbage collected.");
        }
    }
}

Why Are Phantom References Useful?

Phantom references solve problems that weak references cannot handle:

  1. Finalization Tracking:

    • Weak references cannot detect when an object has been finalized; they only indicate when the object is garbage collected.

    • Phantom references ensure that we can track an object's finalization and take appropriate actions before memory is reclaimed.

  2. Post-Finalization Cleanup:

    • Phantom references are used to clean up resources (e.g., close file descriptors, release native memory) associated with an object after it has been finalized.

    • Weak references do not provide such capabilities.

When is an Object Finalized?

Comparison of all four reference types

Aspect

Strong Reference

Soft Reference

Weak Reference

Phantom Reference

Definition

Default type of reference in Java; ensures the object remains in memory.

Prevents object collection unless JVM memory is low.

Allows object collection as soon as no strong references exist.

Tracks object lifecycle post-finalization but does not allow access to the object.

Garbage Collection

Object is never garbage collected unless reference is explicitly cleared or nullified.

Object is garbage collected only if memory is low.

Object is garbage collected immediately after no strong references exist.

Object is collected after finalization, just before memory is reclaimed.

Access to Object

Object is always accessible until explicitly cleared.

Accessible via get() until the object is collected.

Accessible via get() until the object is collected.

Always returns null when accessed via get().

Strength of Reference

Strongest (default behavior in Java).

Weaker than strong references but stronger than weak references.

Weaker than both strong and soft references.

Weakest of all reference types.

Reference Class

No special class required (default reference).

java.lang.ref.SoftReference.

java.lang.ref.WeakReference.

java.lang.ref.PhantomReference.

ReferenceQueue Usage

Not applicable.

Optional (to monitor when object is collected).

Optional (to monitor when object is collected).

Mandatory (used to track objects for cleanup before memory reclamation).

Use Case

General-purpose programming where the object must persist in memory.

Caching, where objects can be retained until memory is needed elsewhere.

Mapping objects (e.g., WeakHashMap), listeners, and avoiding memory leaks.

Post-finalization cleanup, resource deallocation, and advanced resource tracking.

Example Collection

Never garbage collected until explicitly cleared.

Collected only under memory pressure.

Collected as soon as no strong references exist.

Collected after finalization and queued for cleanup.

Last updated