前言
《JVM垃圾回收思維導圖》 系列專題:
- 整理了JVM垃圾回收的基本思想與實現方式
- Java版本爲JDK11
- 參考書籍爲《深入理解Java虛擬機》2020年第三版
系列分爲如下幾塊:
《JVM垃圾回收思維導圖:一. 基本思想》
《JVM垃圾回收思維導圖:二. 理論算法》
《JVM垃圾回收思維導圖:三. HotSpot垃圾回收算法與實現》
五. 垃圾回收概念與算法
PS. 思維導圖大綱
1. 理論(假設)基礎
- 弱分代假說:絕大多數對象都是朝生夕滅的(活的很短)
- 強分代假說:熬過越多次垃圾收集過程的對象,就越難以消亡
- 跨代引用相對於同代引用來說,僅佔極少數
2. 虛擬機實現
垃圾收集器應該將java堆劃分出不同的區域,將對象按照其年齡分配到不同的區域來緩存"
- 新生代(Young Generation)
對朝生夕滅的對象,虛擬機將其分派在新生代區域中。垃圾回收系統只需要關注少量的存活對象,能以較低代價回收到大量的空間
- 老年代(Old Generation)
對於難以消亡的對象,虛擬機將其分派在老年代區域中。垃圾回收系統以較低的頻率去回收此區域的對象,這樣開銷更低效果更好"
- 記憶集(Remembered Set)
- 新生代上建立的一個全局的數據結構
- 記憶集把老年代劃分成若干塊,標出哪一塊內存存在跨代引用
- 發生Minor GC時,只有在[跨代引用關係的小塊內存]裏的對象纔會被加到GC Roots進行掃描,縮小了回收檢索的範圍
3. 垃圾收集
1. 部分收集(Partial GC)
- 新生代收集(Minor GC/Young GC)
目標只是新生代的垃圾收集
- 老年代收集(Major GC/Old GC)
目標只是老年代的垃圾收集
目前只有GMS收集器會有單獨收集老年代的行爲
- 混合收集(Mixed GC)
目標是收集整個新生代以及部分老年代的垃圾收集
目前只有G1收集器有這樣的收集策略
2. 整堆收集(Full GC)
對整個Java堆和方法區的垃圾收集
4. 垃圾收集算法
1. 標記-清除(Mark-Sweep)
- 首先標記需要回收對象;在標記完成後,統一回收掉標記的對象
- 反過來也可以,先標記不需要回收的對象;然後清除掉沒有標記的對象,完成回收
- 最早也是最基礎的收集算法
- 缺點
+ 執行效率不穩定:如果堆中包含大量可回收對象,則效率降低
+ 內存空間存在碎片化:碎片化越來越多可能會引起一次Full GC,花費時間長
2. 標記-複製(Mark-Copy)
- 將內存按容量分爲大小相等的兩塊,每次只用其中一塊
- 當這一塊內存空間用完了,就把其中存活的對象複製到另一塊
- 複製完成後,將前一塊空間全部清除掉做回收
- 兩塊內存空間依次交替使用,來實現垃圾回收
- 缺點:可用內存只有一半,空間浪費嚴重 (實際上,新生代中的對象有98%熬不過第一輪收集 )
- 優化的複製-標記策略 Eden+Servivor
+ 將新生代分爲一塊較大的Eden空間和兩塊較小的Survivor空間
+ 每個具體的時間點,虛擬機只使用一塊Eden和一塊Survivor來儲存對象
+ 垃圾回收時,將其中存活的對象複製到之前沒用到的另一塊Survivor中
+ Hotspot虛擬機的Serial、ParNew等新生代收集器都採用此策略
+ 老年代因爲存活率高,會有大量存活對象,不適合用複製算法
3. 標記-整理(Mark-Compact)
標記整理算法與標記複製很像,不同點在於:不復制,是整理
- 讓所有的對象都向內存空間一端移動,然後直接清理掉邊界以外的內存
- 存活對象過多的話,""移動""對象負重較大,此時必須全程暫停用戶應用程序,會影響效果和體驗
- 不整理(移動)又會出現標記-清除的碎片化
+ 妥協的優化方案
- 讓虛擬機平時多數時間採用標記-清除算法,暫時容忍碎片化存在
- 當碎片化多到影響對象內存分配是,再採用標記-整理算法收集一次
- 基於標記-清除算法的CMS收集器在碎片過多時,會採用此方法"
+ 此算法多用在老年代