Java 提供四種引用類型,與垃圾回收(GC)機制緊密配合,靈活控制物件生命週期。理解它們差異對記憶體優化、快取設計至關重要。
| 引用類型 | 用途 | GC 回收時機 | 典型應用 |
|---|---|---|---|
| Strong Reference (強引用) | 預設引用方式 | 無強引用指向時才回收 | 一般物件持有 |
| Soft Reference (軟引用) | 記憶體不足前保留 | OOM 前回收 | 記憶體敏感快取 |
| Weak Reference (弱引用) | 僅在使用中保留 | GC 發現僅弱引用時回收 | WeakHashMap、監聽器 |
| Phantom Reference (虛擬/幽靈引用) | 追蹤回收時機 | finalize 後、記憶體釋放前 | 資源清理、分散式 GC |
Object referent = new Object();
Object strongRef = referent;
referent = null;
System.gc();
assertNotNull(strongRef); // GC 後仍存在
SoftReference<Object> softRef = new SoftReference<>(referent);
referent = null;
System.gc();
assertNotNull(softRef.get()); // 記憶體充足時保留
WeakReference<Object> weakRef = new WeakReference<>(referent);
referent = null;
System.gc();
assertNull(weakRef.get()); // GC 後立即回收
// WeakHashMap: key 為弱引用,無強引用時自動移除 entry
Map<Object, Object> map = new WeakHashMap<>();
Object key = new Object();
map.put(key, "value");
key = null;
System.gc();
Thread.sleep(1000); // 等待 ReferenceQueue 處理
assertFalse(map.containsValue("value"));
ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> phantomRef = new PhantomReference<>(referent, queue);
// phantomRef.get() 永遠回傳 null
referent = null;
System.gc();
assertTrue(phantomRef.isEnqueued());
Reference<?> removed = queue.remove(); // 取得被回收的引用
assertNotNull(removed);
finalize() 執行後、記憶體真正釋放前入隊,適合資源清理(如 DirectBuffer 釋放、分散式 GC)finalize() 中重建強引用會導致 GC 失敗甚至 OOM,虛擬引用在 finalize 後處理,規避此風險軟、弱、虛擬引用皆可指定 ReferenceQueue,GC 回收物件前將引用入隊,應用程式可輪詢隊列執行清理邏輯(WeakHashMap 即利用此機制清理無效 entry)。
SoftReference 或 Guava Cache / Caffeine 等成熟框架WeakReference 避免記憶體洩漏PhantomReference