首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 四大引用類型深度解析:強、軟、弱、虛引用與 GC 回收機制

     編輯:Java 相關知識

一、引用強度階層

強引用 > 軟引用 > 弱引用 > 虛引用

引用類型回收時機典型用途需配合 ReferenceQueue
StrongReference永不主動回收(OOM 拋異常)通用物件持有否
SoftReference記憶體不足時記憶體敏感緩存(圖片、網頁快取)可選
WeakReferenceGC 掃描到即回收監聽器、回調、WeakHashMap 鍵可選
PhantomReferenceGC 回收前(finalize 後)精確追蹤回收、DirectBuffer 釋放必須

二、代碼實戰驗證

1. 強引用:GC 不回收

Object strong = new Object();
System.gc(); // 不會回收 strong 指向的物件

2. 軟引用:記憶體不足才回收

SoftReference soft = new SoftReference<>(new Object());
// 模擬 OOM 前,JVM 會嘗試清理軟引用
// 可配合 ReferenceQueue 獲知被回收
ReferenceQueue q = new ReferenceQueue<>();
SoftReference soft2 = new SoftReference<>(new Object(), q);

3. 弱引用:GC 即回收

WeakReference weak = new WeakReference<>(new Object());
System.gc(); // 下次 GC 必回收
// WeakHashMap 內部鍵即為 WeakReference,鍵無強引用時自動移除條目

4. 虛引用:回收前通知,必須配隊列

ReferenceQueue pq = new ReferenceQueue<>();
PhantomReference phantom = new PhantomReference<>(new Object(), pq);
// 物件被回收前,phantom 會被加入 pq
// 典型用途:Netty/DirectByteBuffer 釋放堆外記憶體

三、ReferenceQueue 運作機制

ReferenceQueue queue = new ReferenceQueue<>();
// 某引用被 GC 回收後,JVM 將該 Reference 物件入隊
// 消費者執行緒輪詢
new Thread(() -> {
    while (true) {
        Reference ref = queue.remove(); // 阻塞等待
        // 執行清理邏輯:關閉資源、釋放堆外記憶體、移除快取條目
    }
}).start();

四、實際應用場景

1. 軟引用:圖片/網路資源快取

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));
}

2. 弱引用:監聽器模式防洩漏

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();
        }
    }
}

3. 虛引用:堆外記憶體釋放

DirectByteBuffer 建立時註冊 Cleaner(繼承 PhantomReference),GC 回收 DirectByteBuffer 物件前,Cleaner 入隊,專用執行緒調用 freeMemory(address) 釋放堆外記憶體,避免 finalize 不確定性與效能問題。

五、常見誤區

  • 誤以為 SoftReference 一定能防 OOM:JVM 可能來不及清理就拋 OOM;大型快取建議用 Caffeine/Ehcache 等成熟框架。
  • WeakReference 立即回收:需等待下一次 GC,且 GC 為低優先級執行緒,不保證即時性。
  • PhantomReference.get() 永遠返回 null:只能透過隊列感知回收事件,無法取得被引用物件。

六、總結

強引用:正常開發主力;
軟引用:緩存首選,記憶體不夠再丟;
弱引用:輔助結構(監聽器、WeakHashMap),隨緣回收;
虛引用:資源精確釋放利器,必配隊列,get() 為 null。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved