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

JVM 記憶體管理:分代收集算法深度解析

     編輯:Java 相關知識

引言

所謂的「終極算法」其實就是當前 JVM 採用的分代收集算法,但這並非真正的終點。隨著技術演進,未來必然會出現更優秀的演算法,這也是技術大牛們持續探索的方向。那麼,分代收集算法究竟是如何處理垃圾回收(GC)的呢?

物件分類:依據生命週期劃分

分代收集算法的核心思想是針對物件的不同特性採用適合的演算法,它並非創造了新演算法,而是將前三種經典演算法(標記-清除、複製、標記-整理)進行實戰組合。首先,我們將堆中物件按生命週期長短分為三類:

  • 夭折物件:朝生夕滅,存活極短。典型例子包括方法局部變數、迴圈內的臨時變數等。
  • 老不死物件:存活時間較長,如緩存物件、資料庫連線、單例物件等。雖然最終多會消亡,但存活率極高。
  • 不滅物件:幾乎永久存活,如字串常量池物件、已載入的類資訊等,主要位於方法區(HotSpot 中稱永久代)。

物件對應的記憶體區域

JVM 將堆劃分為新生代(年輕代)與老年代(年老代),方法區獨立存在。夭折與老不死物件位於 Java 堆,不滅物件位於方法區。JVM 規範要求對堆實現 GC,但對方法區 GC 不強制,因此若 JVM 未實現方法區 GC,不滅物件將真正「不滅」。分代收集算法主要針對 Java 堆(新生代與老年代)設計。

新生代:夭折物件的收集——複製演算法

新生代物件存活率低,極適合使用複製演算法。為解決 50% 記憶體浪費問題,HotSpot 採用 8:1:1 的 Eden、From Survivor、To Survivor 結構:

  • 新物件優先分配在 Eden 區(80%)。
  • GC 時,將 Eden 和 From Survivor 中存活物件複製到 To Survivor。
  • 清空 Eden 和 From Survivor,角色互換。
  • 僅浪費 10% Survivor 空間,換取記憶體連續與高速 GC。

新生代 GC 流程圖

若存活物件超過 Survivor 容量,多餘物件直接進入老年代作為「備用倉庫」。

老年代:老不死物件的收集——標記-整理/標記-清除

老年代物件存活率極高,複製演算法不再適用(無備用空間且複製成本高)。因此採用標記-整理或標記-清除演算法,雖效率較低,但能解決記憶體碎片問題。

物件晉升老年代的兩大條件:

  1. 年齡達到閾值(經過若干次 Minor GC 仍存活)。
  2. 新生代 Survivor 區放不下的大物件或長期存活物件。

方法區:不滅物件的回收

方法區(永久代)主要回收廢棄常量與無用類。回收條件嚴格,且採用與老年代類似的標記-清除/整理演算法。JDK 8 起永久代被元空間取代,但回收邏輯類似。

GC 觸發時機:Minor GC vs Full GC

  • Minor GC(普通 GC):僅回收新生代,頻率高、速度快。
  • Full GC(全局 GC):回收老年代,常伴隨新生代、永久代回收,耗時長,觸發條件較嚴格(如老年代空間不足、永久代空間不足、System.gc() 等)。

由於老年代與永久代回收效果較差且增長緩慢,通常經過多次 Minor GC 才觸發一次 Full GC。

結語

分代收集算法是 JVM GC 的基石,理解其原理對排查記憶體溢出、優化 GC 停頓至關重要。下一章將探討具體的垃圾收集器實現(如 Serial、Parallel、CMS、G1 等)。

作者:zuoxiaolong(左潇龍)
出處:博客園左潇龍的技術博客

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