jvm系列之垃圾收集演算法
jvm系列之垃圾收集演算法
1 標記-清除演算法
標記-清除演算法是最基礎的演算法,演算法分為標記和清除兩個階段,首先標記出要清除的物件,在標記完後統一回收所有被標記的物件,標記方式為j《jvm系列之垃圾收集器》裡面所提到的。這種演算法標記和清除兩個過程效率都不高;並且在標記清除後,記憶體空間變得很零散,產生大量記憶體碎片。當需要分配一個比較大的物件時有可能會導致找不到足夠大的記憶體。
標記清除演算法圖解(圖片來源於百度圖片):

timg.jpg
為了解決標記清除效率低的問題,出現了複製演算法;這種演算法將記憶體劃分為大小相等的兩塊記憶體,只使用其中一塊。當這一塊記憶體使用完了就將存活的物件複製到另一塊上面去,然後把已使用的記憶體空間一次性清理掉,這種方法不必考慮記憶體碎片的情況,執行高效,實現簡單。缺點是浪費了一半的記憶體。複製演算法圖解(圖片來源百度圖片):

timg (1).jpg
3 標記-整理演算法
複製收集演算法在物件存活率較高的時候就要進行較多的複製操作,導致效率變低。而且老年代很少會有記憶體回收,對老年代而言,複製演算法做了大量的無用功。針對複製演算法存在的的問題,有人提出了標記-整理演算法。標記過程和標記-清除演算法過程一樣,但後續不是直接對可回收物件進行清理,而是讓所有存活物件都向一方移動,整理記憶體,然後再進行清理。標記-整理演算法圖解(圖片來源百度圖片):

timg (2).jpg
4 分代收集演算法
分代收集演算法思路是根據物件存活週期不同將記憶體劃分為幾塊。一般是分為新生代和老年代,這樣就可以根據各個年代的特點採用最適當的收集演算法。在新生代中每次收集時都會回收很多記憶體,選用高效率的複製演算法,並且只需要預留少量的複製空間,用於複製存活物件。老年代中因為物件存活率高,採用標記-整理或標記清理演算法節省記憶體空間提高清理效率。
5 各版本jdk垃圾收集器一覽
收集器名稱 | 區 域 | 說明 |
---|---|---|
Serial | 新生代 | 單執行緒,GC時必須停止其它執行緒直到收集結束;JVM執行在client模式下新生代的預設收集器,簡單有效;採用複製演算法 |
ParNew | 新生代 | Serial收集的多執行緒版,保留Serial的引數控制,演算法等,暫停所有使用者執行緒,採用複製演算法;JVM執行在server的首先的新生代收集器;只有它能和CMS配合工作 |
Parallel Scavenge | 新生代 | 採用複製演算法,並行的多執行緒收集器,與ParNew不同的是,關注點不是停頓時間,而是可控制的吞吐量,即執行使用者程式碼的時間/(執行使用者程式碼的時間+垃圾收集的時間)。可設定最大GC時間和吞吐量大小等引數,也可以讓JVM自適應調整策略 |
CMS | 新生代 | concurrent Mark Sweep,已獲取最短回收停頓為目標,大部分的網際網路站及服務端採用的方式,標記-清除演算法 |
G1 | 新生代/老年代 | 收集器最前沿版本,JDK 1.7,代替CMS的新產品 |
Serial Old(MSC) | 老年代 | Serial的老年版,單執行緒收集器,採用標記-整理演算法,主要是client模式的JVM使用 |
Parallel Old | 老年代 | Parallel Scavenge的老年版,多執行緒,標記整理演算法 |
jdk11 垃圾收集器——ZGC
(網上搜的)ZGC是一個處於實驗階段的,可擴充套件的低延遲垃圾回收器,旨在實現以下幾個目標:
- 停頓時間不超過10ms
- 停頓時間不隨heap大小或存活物件大小增大而增大
- 可以處理從幾百兆到幾T的記憶體大小
限制:
- 當前版本不支援類解除安裝
- 當前版本不支援JVMCI
ZGC包含10個階段,但是主要是兩個階段標記和relocating。GC迴圈從標記階段開始,遞迴標記所有可達物件,標記階段結束時,ZGC可以知道哪些物件仍然存在哪些是垃圾。ZGC將結果儲存在每一頁的點陣圖(稱為live map)中。在標記階段,應用執行緒中的load barrier將未標記的引用壓入執行緒本地的標記緩衝區。一旦緩衝區滿,GC執行緒會拿到緩衝區的所有權,並且遞迴遍歷此緩衝區所有可達物件。注意:應用執行緒負責壓入緩衝區,GC執行緒負責遞迴遍歷。
標記階段後,ZGC需要遷移relocate集中的所有物件。relocate集是一組頁面集合,包含了根據某些標準(例如那些包含最多垃圾物件的頁面)確定的需要遷移的頁面。物件由GC執行緒或者應用執行緒遷移(通過load barrier)。ZGC為每個relocate集中的頁面分配了轉發表。轉發表是一個雜湊對映,它儲存一個物件已被遷移到的地址(如果該物件已經被遷移)。GC執行緒遍歷relocate集的活動物件,並遷移尚未遷移的所有物件。有時候會發生應用執行緒和GC執行緒同時試圖遷移同一個物件,在這種情況下,ZGC使用CAS操作來確定勝利者。一旦GC執行緒完成了relocate集的處理,遷移階段就完成了。雖然這時所有物件都已遷移,但是舊地引用址仍然有可能被使用,仍然需要通過轉發表重新對映(remapping)。然後通過load barrier或者等到下一個標記迴圈修復這些引用。