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

Java 弱引用 WeakReference 原理與實戰解析

     編輯:Java 綜合教學

引用類型體系

WeakReference 使用示例

public class TestWeakReference {
    public static void main(String[] args) throws Exception {
        UserInfo user = new UserInfo("Jim Green");
        UserInfo strongRef = user; // 強引用
        WeakReference<UserInfo> weakRef = new WeakReference<>(user);

        System.out.println("GC 前 - 強引用: " + strongRef);
        System.out.println("GC 前 - 弱引用: " + weakRef.get());

        user = null; // 斷開原強引用
        System.gc(); // 請求 GC

        System.out.println("GC 後 - 強引用: " + strongRef); // 仍存在
        System.out.println("GC 後 - 弱引用: " + weakRef.get()); // 仍存在(因 strongRef 仍指向)

        strongRef = new UserInfo("Jim White"); // 覆蓋強引用
        System.gc();

        System.out.println("再次 GC - 強引用: " + strongRef);
        System.out.println("再次 GC - 弱引用: " + weakRef.get()); // null,已被回收
    }
}

class UserInfo {
    private String name;
    public UserInfo(String name) { this.name = name; }
    @Override public String toString() { return "Name: " + name; }
}

輸出結果

GC 前 - 強引用: Name: Jim Green
GC 前 - 弱引用: Name: Jim Green
GC 後 - 強引用: Name: Jim Green
GC 後 - 弱引用: Name: Jim Green
再次 GC - 強引用: Name: Jim White
再次 GC - 弱引用: null

內部實現原理

UML 關係

  • Reference (抽象基類) → WeakReference (簡單繼承)
  • ReferenceQueue:GC 將回收的引用入隊,供應用輪詢。

Reference 核心字段

private T referent;           // 所引用的物件
private ReferenceQueue<? super T> queue; // 可選隊列
private Reference next;       // 隊列節點指針
// 狀態隱式由 next 指向判斷:null=Active, this=Inactive/Enqueued 末尾, 其他=隊列中

四種狀態流轉

  1. Active:剛建立,next=null。
  2. Pending:GC 發現 referent 可回收且有 queue,放入 pending 靜態鏈表。
  3. Enqueued:ReferenceHandler 守護線程處理 pending,入 queue,next 指向隊列下一個。
  4. Inactive:從 queue 移除或無 queue 直接轉入,next=this。

ReferenceHandler 守護線程

private static class ReferenceHandler extends Thread {
    public void run() {
        for (;;) {
            Reference r;
            synchronized (lock) {
                if (pending != null) {
                    r = pending;
                    pending = (r.next == r) ? null : r.next;
                    r.next = r; // 標記為 Enqueued
                } else {
                    lock.wait(); // 等待 GC 喚醒
                }
            }
            if (r instanceof Cleaner) ((Cleaner)r).clean();
            else if (r.queue != ReferenceQueue.NULL) r.queue.enqueue(r);
        }
    }
}

關鍵點:GC 負責 Active→Pending,ReferenceHandler 負責 Pending→Enqueued。

ReferenceQueue 入隊/出隊

boolean enqueue(Reference<? extends T> r) {
    synchronized (r) {
        if (r.queue == ENQUEUED) return false;
        synchronized (lock) {
            r.queue = ENQUEUED;
            r.next = (head == null) ? r : head; // 頭插法
            head = r;
            queueLength++;
            lock.notifyAll();
            return true;
        }
    }
}

WeakHashMap 原理預覽

  • Key 使用 WeakReference,Value 為強引用。
  • 當 Key 無強引用時,GC 回收 Key,對應 Entry 在下次操作 (get/put/resize) 時被清理。
  • 適合「Key 生命週期由外部控制」的快取場景。

總結

  • WeakReference 讓物件在「無強引用時」可被 GC 回收。
  • 配合 ReferenceQueue 可感知回收事件,做清理工作。
  • 實現依賴 GC 與 ReferenceHandler 協作,狀態由 next 指針隱式標記。
  • 濫用會導致頻繁 GC、效能抖動,請謹慎使用。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
引用類型強度回收時機典型用途
Strong Reference最強永不主動回收一般物件持有
Soft Reference次強記憶體不足 (OOM) 前快取、圖片緩存
Weak Reference弱下次 GC 時快取、監聽器、WeakHashMap Key
Phantom Reference最弱最終化後、回收前直接記憶體釋放追蹤