強引用 > 軟引用 > 弱引用 > 虛引用
| 引用類型 | 回收時機 | 典型用途 | 需配合 ReferenceQueue |
|---|---|---|---|
| StrongReference | 永不主動回收(OOM 拋異常) | 通用物件持有 | 否 |
| SoftReference | 記憶體不足時 | 記憶體敏感緩存(圖片、網頁快取) | 可選 |
| WeakReference | GC 掃描到即回收 | 監聽器、回調、WeakHashMap 鍵 | 可選 |
| PhantomReference | GC 回收前(finalize 後) | 精確追蹤回收、DirectBuffer 釋放 | 必須 |
Object strong = new Object(); System.gc(); // 不會回收 strong 指向的物件
SoftReference
WeakReferenceweak = new WeakReference<>(new Object()); System.gc(); // 下次 GC 必回收 // WeakHashMap 內部鍵即為 WeakReference,鍵無強引用時自動移除條目
ReferenceQueuepq = new ReferenceQueue<>(); PhantomReference phantom = new PhantomReference<>(new Object(), pq); // 物件被回收前,phantom 會被加入 pq // 典型用途:Netty/DirectByteBuffer 釋放堆外記憶體
ReferenceQueuequeue = new ReferenceQueue<>(); // 某引用被 GC 回收後,JVM 將該 Reference 物件入隊 // 消費者執行緒輪詢 new Thread(() -> { while (true) { Reference extends MyObj> ref = queue.remove(); // 阻塞等待 // 執行清理邏輯:關閉資源、釋放堆外記憶體、移除快取條目 } }).start();
Map> imageCache = new HashMap<>(); // 獲取 SoftReference ref = imageCache.get(url); Bitmap bmp = ref != null ? ref.get() : null; if (bmp == null) { bmp = downloadImage(url); imageCache.put(url, new SoftReference<>(bmp)); }
class EventSource {
List> listeners = new ArrayList<>();
void add(Listener l) { listeners.add(new WeakReference<>(l)); }
void fire() {
listeners.removeIf(ref -> ref.get() == null); // 清理失效
for (WeakReference ref : listeners) {
Listener l = ref.get();
if (l != null) l.onEvent();
}
}
}
DirectByteBuffer 建立時註冊 Cleaner(繼承 PhantomReference),GC 回收 DirectByteBuffer 物件前,Cleaner 入隊,專用執行緒調用 freeMemory(address) 釋放堆外記憶體,避免 finalize 不確定性與效能問題。
強引用:正常開發主力;
軟引用:緩存首選,記憶體不夠再丟;
弱引用:輔助結構(監聽器、WeakHashMap),隨緣回收;
虛引用:資源精確釋放利器,必配隊列,get() 為 null。