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

Java 垃圾回收機制全景解析:從算法到調優實戰

     編輯:Java 相關知識

一、垃圾回收的意義與權衡

在 C/C++ 中,對象佔用的內存需手動釋放;Java 引入 GC 自動管理內存:當無引用指向對象時,JVM 系統線程自動回收其佔用空間。GC 不僅釋放無用對象,還能整理內存碎片(將存活對象移至堆一端,騰出連續空間)。

優點:

  • 提高編程效率:避免手動內存管理的複雜錯誤
  • 保護程序完整性:是 Java 安全策略核心部分

潛在缺點:

  • 性能開銷:追蹤有用對象、釋放無用對象消耗 CPU 時間
  • 早期算法不完備:無法 100% 回收所有廢棄內存(現代算法已大幅改善)

二、垃圾收集算法演進

所有 GC 算法核心做兩件事:發現無用對象、回收其佔用內存。主流算法均基於根集概念:正在執行的 Java 程序可訪問的引用變量集合(局部變量、參數、類變量)。

1. 引用計數法

  • 每個對象有引用計數器,賦值加 1,離開作用域減 1,歸零即可回收
  • 優點:執行快、不長時間中斷程序、適合實時系統
  • 缺點:增加程序執行開銷;無法處理循環引用

2. 追蹤算法 / 標記-清除

  • 從根集掃描,標記可達對象,清除不可達對象
  • 解決了循環引用問題

3. 壓縮算法

  • 清除過程中將所有對象移至堆一端,形成連續空閒區
  • 需更新所有引用指向新位置,通常引入句柄表間接訪問

4. 複制算法

  • 堆分為對象區和空閒區,GC 時將活動對象複製到空閒區,角色互換
  • 典型:Stop-and-copy(切換過程中程序暫停)
  • 優點:無碎片、分配簡單(指針碰撞)
  • 缺點:浪費一半空間;需複製所有存活對象

5. 分代算法(現代商用 JVM 主流)

  • 堆分為新生代、老年代(甚至更多代)
  • 新生代:對象朝生夕死 → 複制算法(僅複製少量存活對象)
  • 老年代:對象存活率高 → 標記-清除/整理
  • 優點:針對不同代特點選擇最優算法,大幅提升效率

6. 自適應算法

  • 監控堆使用情況,動態選擇最適合的收集算法

三、System.gc() 與命令行觀察

  • System.gc():僅是建議,JVM 不保證立即執行,只會增加 GC 發生概率
  • -verbose:gc:啟動時輸出 GC 日誌,格式如 [Full GC 168K->97K(1984K), 0.0253873 secs]
    • 箭頭前後:GC 前後存活對象佔用內存
    • 括號內:堆總容量
    • 時間:GC 耗時

四、finalize() 方法深度剖析

protected void finalize() throws Throwable
  • 對象被 GC 回收前調用,用於釋放非 Java 堆內存資源(如 JNI 分配的內存、文件句柄、數據庫連接)
  • 調用時機不確定,不建議依賴它釋放關鍵資源
  • 優先使用 try-with-resources、AutoCloseable、Cleaner(Java 9+)
  • 任何對象 finalize() 只會被調用一次

五、主 GC 觸發條件

  1. 應用程序空閒時: GC 線程優先級最低,僅在無用戶線程運行時執行
  2. Java 堆內存不足時: 創建新對象空間不足 → 強制觸發 GC → 若仍不足再試兩次 → 拋出 OutOfMemoryError

主 GC 具有不確定性,長期運行應用會反覆觸發。

六、減少 GC 開銷的工程實踐

措施原理代碼示例
不顯式調用 System.gc()避免增加 Full GC 頻率—
減少臨時對象創建減少垃圾產生,延長 Minor GC 間隔循環外複用對象、使用 StringBuilder
對象不用時置 null幫助 GC 更快識別垃圾list = null; map.clear();
字符串拼接用 StringBuilder避免產生大量中間 String 對象new StringBuilder().append(a).append(b)
優先用基本類型int 比 Integer 佔用內存少得多int count vs Integer count
少用靜態變量靜態變量生命周期長,不易被回收—
分散對象創建/刪除時間避免瞬間大量分配觸發 Full GC批量處理改為流式/分批

七、GC 核心特點與最佳實踐總結

  1. 不可預知性: 不要假定 GC 發生時間
  2. 精確性: 精確標記存活對象、精確定位引用關係,防止內存洩漏與碎片
  3. 多樣性: 多種收集器並存,有 STW、並發、並行等不同模式
  4. JVM 耦合性: 實現與具體 JVM、內存模型緊密相關
  5. 可配置性: 現代 GC 提供豐富參數,可根據應用環境調優

開發者注意事項:

  • 不要假定 GC 時間
  • System.gc() 不保證執行
  • 選擇適合的收集器(無特殊需求用默認;實時系統考慮增量/並行;高配服務器考慮並行標記/清除)
  • 防止內存洩漏是關鍵:良好編程習慣、及時釋放引用、去除監聽器
  • 盡早釋放無用引用:離開作用域自動置 null,注意移除監聽器後再置空

參考:《深入理解 Java 虛擬機》

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