Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Java

Các loại Reference (Tham chiếu) trong Java: Strong, Weak, Soft, Phantom

Java định nghĩa 4 mức độ reference strength (độ mạnh tham chiếu) quyết định khi nào object được Garbage Collector (GC) thu hồi. Mạnh nhất → Yếu nhất: Strong > Soft > Weak > Phantom.

1. Strong Reference (Tham chiếu mạnh) – Mặc định

  • Tạo bằng: Object obj = new Object();
  • Object không bao giờ bị GC thu hồi miễn là strong reference còn tồn tại.
  • Chỉ bị thu hồi khi reference = null hoặc ra khỏi scope.
public class StrongRefDemo {
    public static void main(String[] args) {
        Demo obj = new Demo(); // Strong reference
        obj = null;            // Bỏ strong reference → eligible for GC
    }
}
class Demo { /* ... */ }

2. Weak Reference (Tham chiếu yếu) – java.lang.ref.WeakReference

  • GC thu hồi object ở mọi GC cycle (không chờ memory pressure).
  • Dùng cho: WeakHashMap (key weak), listener registry, canonicalizing maps.
  • Tạo: WeakReference ref = new WeakReference<>(obj);
  • ref.get() trả về object hoặc null nếu đã GC.
import java.lang.ref.WeakReference;

public class WeakRefDemo {
    public static void main(String[] args) {
        Demo obj = new Demo();
        obj.display(); // Hello
        
        WeakReference weakRef = new WeakReference<>(obj);
        obj = null; // Chỉ còn weak reference
        
        System.gc(); // Yêu cầu GC
        try { Thread.sleep(100); } catch (InterruptedException e) {}
        
        Demo retrieved = weakRef.get();
        if (retrieved != null) retrieved.display();
        else System.out.println("Object đã bị GC reclaim");
    }
}
class Demo { void display() { System.out.println("Hello"); } }

3. Soft Reference (Tham chiếu mềm) – java.lang.ref.SoftReference

  • GC chỉ thu hồi khi JVM sắp OOM (OutOfMemoryError).
  • Thích hợp: Cache (image, parsed data, computed results) – tự động evict khi memory áp lực.
  • Cũng có thể dùng ReferenceQueue để cleanup.
import java.lang.ref.SoftReference;

public class SoftRefDemo {
    public static void main(String[] args) {
        Demo obj = new Demo();
        obj.display();
        
        SoftReference softRef = new SoftReference<>(obj);
        obj = null;
        
        System.out.println("Before GC: " + softRef.get()); // Object còn lại
        
        // Giả lập memory pressure (khó kiểm soát chính xác)
        System.gc();
        try { Thread.sleep(100); } catch (InterruptedException e) {}
        
        System.out.println("After GC: " + softRef.get()); // Vẫn có thể còn (nếu memory đủ)
    }
}

4. Phantom Reference (Tham chiếu ảo) – java.lang.ref.PhantomReference

  • Object đã finalized (nếu có) nhưng chưa bị reclaim vật lý.
  • phantomRef.get() LUÔN TRẢ VỀ NULL – không thể revive object.
  • BẮT BUỘC đăng ký với ReferenceQueue.
  • Khi object phantom-reachable → reference được enqueue vào queue.
  • Dùng cho: Pre-mortem cleanup (giải phóng native memory, file handle, off-heap resource) – thay thế finalize().
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class PhantomRefDemo {
    public static void main(String[] args) throws InterruptedException {
        ReferenceQueue queue = new ReferenceQueue<>();
        Demo obj = new Demo();
        
        PhantomReference phantomRef = new PhantomReference<>(obj, queue);
        System.out.println("phantomRef.get() = " + phantomRef.get()); // null
        
        obj = null;
        System.gc();
        
        // Chờ enqueue (blocking)
        PhantomReference ref = (PhantomReference) queue.remove(3000);
        if (ref != null) {
            System.out.println("Object phantom reachable! Cleanup native resources here.");
            // cleanup code...
        }
    }
}
class Demo { /* native resource handle */ }

So sánh tổng hợp

LoạiGC Reclaimget()ReferenceQueueUse Case Chính
StrongKhông (khi reachable)ObjectKhôngBiến thông thường
SoftKhi JVM cần memory (OOM imminent)Object / nullOptionalMemory-sensitive Cache
WeakMọi GC cycleObject / nullOptionalWeakHashMap, Listeners, Canonicalizing
PhantomSau finalize, trước reclaimLuôn nullBắt buộcPre-mortem cleanup (native, off-heap)

Cleaner API (Java 9+) – Thay thế PhantomReference dễ dùng hơn

import java.lang.ref.Cleaner;

public class CleanerDemo {
    private static final Cleaner cleaner = Cleaner.create();
    
    static class NativeResource implements Runnable {
        private final long handle;
        NativeResource(long h) { this.handle = h; }
        public void run() { 
            // Cleanup native resource
            System.out.println("Freeing native handle: " + handle); 
        }
    }
    
    public static void main(String[] args) {
        NativeResource res = new NativeResource(123);
        Cleaner.Cleanable cleanable = cleaner.register(res, res);
        // Khi res bị GC → run() được gọi tự động
        res = null;
        System.gc();
    }
}

Tóm tắt chọn lựa

  • Strong: Mặc định, hầu hết trường hợp.
  • Soft: Cache có thể tái tạo, muốn giữ lâu nếu memory cho phép.
  • Weak: Metadata gắn với object (key map, listener), object có thể đi bất cứ lúc nào.
  • Phantom/Cleaner: Cleanup tài nguyên native/off-heap, thay thế finalize().