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

Effective Java 條目 6:消除過期對象引用,防止內存洩漏

     編輯:Java 相關知識

誤區澄清

「Java 有 GC 就不會內存洩漏」是錯誤認知。內存洩漏 = 對象可達但不再使用。GC 僅回收不可達對象,若程序持有過期引用 (Obsolete Reference),對象永不可達,導致內存耗盡。

經典案例:棧實現內存洩漏

有問題的實現

public class Stack {
    private Object[] elements;
    private int size = 0;
    public void push(Object e) { elements[size++] = e; }
    public Object pop() {
        if (size == 0) throw new EmptyStackException();
        return elements[--size]; // 過期引用殘留在 elements[size] 中!
    }
}

彈出元素後,數組該位置仍持有引用,GC 無法回收,隨著反覆 push/pop 內存無限增長。

修正版

public Object pop() {
    if (size == 0) throw new EmptyStackException();
    Object result = elements[--size];
    elements[size] = null; // 手動清空過期引用
    return result;
}

常見內存洩漏場景

場景原因對策
靜態集合 (HashMap/Vector) 累積對象
靜態變量生命周期 = 應用生命周期,元素無法釋放
及時 remove() 或置空集合引用
監聽器/回調未註銷
註冊 addListener 後未 removeListener,源對象持有監聽器引用
生命周期結束時顯式移除,或使用弱引用
連接池資源未關閉
Connection/Statement/ResultSet 未 close,物理連接泄漏
try-with-resources 或 finally 塊確保關閉
ThreadLocal 未清理
線程池線程復用,ThreadLocal 值隨線程存活
使用完畢調用 remove()
緩存無過期策略
無界緩存持續增長
使用 Guava Cache / Caffeine 設置最大容量與過期時間

最佳實踐清單

  1. 作用域最小化:變量在最內層作用域聲明,循環體內而非外部
  2. 及時置空:數組、集合、字段不再使用時顯式賦 null
  3. 弱引用輔助:緩存、監聽器、回調考慮 WeakReference / WeakHashMap
  4. 資源自動管理:JDBC、IO、鎖均使用 try-with-resources
  5. 輪廓分析工具:VisualVM、JProfiler、Arthas 定期排查堆積對象

總結

消除過期引用是 Java 內存管理的核心技能。GC 不是萬能藥,開發者必須對對象生命周期負責,在恰當時機切斷引用鏈,讓 GC 高效工作。

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