天天看點

垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器

垃圾收集器回收種類

垃圾收集器是垃圾回收算法的具體實作

垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器

 串行垃圾回收器(Serial)

它為單線程環境設計且隻使用一個線程進行垃圾回收,會暫停使用者線程

(并行垃圾回收器)Parallel 

多個垃圾收集器并行工作,此時使用者線程是暫停的

并發垃圾回收器(CMS)

使用者線程和垃圾收集線程同時執行(不一定是并行,可能是交替執行,不需要停頓使用者線程)

垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器

 G1垃圾回收器  

G1垃圾回收器将堆記憶體分割成不同的區域然後并發的對其進行垃圾回收

 七種垃圾收集器

垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器
垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器
垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器

Serial

Serial,最基本最老的收集器。其存在的主要問題是"Stop The World",即在垃圾回收的時候,必須要暫停所有的其他工作線程,直到收集完成。此外在工作的時候,其垃圾收集線程是單線程的。

ParNew

ParNew 其實就是 Serial 的多線程版本。其除了垃圾收集線程是多線程意外,其他功能與 Serial 一樣,如收集算法、Stop The World 的特性、對象配置設定規則、回收政策等。

Parallel Scavenge

Parallel Scavenge 大多數特性與 ParNew 相似,其最主要的特點是其設計的目标是達到一個 可控制的吞吐量,所謂吞吐量就是 CPU 用于運作使用者代碼的時間和 CPU 總消耗時間的比值,即 吞吐量 = 運作使用者代碼時間 / (運作使用者代碼時間 + 垃圾收集時間)。高吞吐量意味着高效率地利用 CPU 時間,盡快完成程式計算任務,适合在背景運算而不需要太多互動的任務。

Serial Old

其是 Serial 的老年代版本,其他特性和 Serial 類似,不多贅述。

Parallel Old

其是 Parallel Scavenge 的老年代版本,适合跟 Parallel Scavenge 一起組成一個 吞吐量優先 的收集組合。

CMS

CMS的全稱為 Concurrent Mark Sweep,其設計理念是擷取最短回收停頓時間。其回收步驟為

  1. 初始标記
  2. 并發标記
  3. 重新标記
  4. 并發清除

初始标記是簡單标記一下 GC Roots 能關聯到的對象,是以速度很快。并發标記則需要進行 GC Roots Tracing,重新标記是為了修正在并發标記期間因使用者程式繼續運作而導緻标記産生變動的對象,最終執行并發清除過程。

在收集過程中,隻有初始标記和重新标記需要 Stop The World, 耗時較多。而耗時較多的并發标記和并發清除階段都是可以和使用者線程一起執行的,是以其可以大大減少停頓時間。

垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器

從CMS的執行模型中,我們也可以看到其擁有以下缺點。

首先我們看到整個 GC 在第 4步是并發清除的,那麼在清除過程中就會産生 浮動垃圾 ,因為此時使用者線程還在繼續執行,是以必然會産生新的垃圾,而這些垃圾因為已經錯過了這次的标記,就需要等到下次才能被回收。

此外也正是因為并發清除的原因, JVM 需要為使用者運作過程産生的對象預留白間,那麼這個度又該如何把握呢?如果預留的少了,就會出現 "Concurrent Mode Failure" 失敗,此時 JVM 會啟用後備方案:Serial Old,那麼就會導緻較長時間的停頓。如果預留的多了,那麼就會頻繁地進行 Full GC,影響性能。

并且因為清除階段采用的是并發清除,那麼使用者線程因為在執行的原因,就必然隻能采用 标記-清除算法 ,這樣就會導緻産生大量的記憶體碎片。

最後因為 CMS 是一個針對并發模型的實作,那麼在并發階段就必然會占用 CPU 時間,這就必然會導緻應用程式變慢,因為這個是所有針對并發進行設計的程式都會有的問題。

G1

Garbage-First 算法的核心觀念是将堆劃分為多個大小相等的獨立區域——Region(還保留着新生代和老年代,但其不再是實體隔離的,而是一系列region的集合)。

在程式運作過程中,G1 會維護一個 優先級清單,裡面記錄着各個 Region 的垃圾堆積價值(回收所獲得大小和回收所需時間的比值),這樣在每次回收的時候,根據 允許的回收時間,優先回收價值最大的 Region,通過這樣,我們的 GC 時間就是可預測的。

但是聽着将堆劃分為多個 Region 很簡單,在實際情況下,我們該如何保證 Region 以及其中對象的獨立性呢?

實際上,Region 不可能是獨立的,因為一個對象配置設定到這個 Region 上,但其可能會被堆上的任一個引用所關聯。這樣在進行可達性分析的時候,難道意味着要進行 全堆掃描 嗎?如果這樣的話,性能又該如何保證呢?

是以 G1 使用了 Remembered Set 來避免這一現象。在程式對 Reference 類型資料進行寫操作時,其會産生一個 Write Barrier 暫時中斷寫操作,來檢查 Reference 引用對象是否處于不同的 Region 中,如果是,則通過 CardTable 将相關引用資訊記錄到對象所屬 Region 的 Remembered Set 中,這樣在進行記憶體回收,可達性分析的時候通過 Remembered Set 則可以保證不對全堆掃描也不會有遺漏。

G1 詳細的執行流程如下:

  1. 初始标記
  2. 并發标記
  3. 最終标記
  4. 篩選回收

粗略來看,G1 的前 3個步驟和 CMS 十分類似。但其内部還是有些不一樣。

首先是初始标記階段,G1 和 CMS 類似,也隻是标記一下 GC Roots 能直接關聯到的對象,但其還修改了 TAMS(Next Top at Mark Start)的值,讓下一階段并發标記時,使用者線程可以正确的在可用 Region 中建立對象。并發标記階段和 CMS 一樣,但将這段時間對象變化記錄存儲在 Remembered Set Log 中;在最終标記階段,将 Remembered Set Log 合并到 Remembered Set 中,最終在篩選回收階段首先對 各個 Region 的價值進行排序,然後根據使用者設定的回收時間來制定回收計劃。

垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器
垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器

CMS和G1的對比:

G1是為了替代CMS而存在的。在以下方面表現的更出色:

G1是一個有整理記憶體過程的垃圾收集器,不會産生很多的記憶體碎片

G1的STW更可控,G1在停頓時間尚增加了預測機制,使用者可以指定期望停頓時間

※G1底層原理

垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器

 對象特别大直接在分給多個區域來裝 :humongous區域 (如果一個對象占用的空間超過了分區容量50%以上,G1收集器就認為這是個巨型對象,這些對象預設直接會被配置設定到老年代,但是如果他是一個但其存在的巨型對象,G1就會劃分一個humongous區域來進行存放,如果一個H區放不下,就會去找連續的H區,但是找不到就會不得不進行FullGC)

在非G1收集器是如何裝大對象得?

垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器

G1算法将堆分為諾幹個區域,它們任然屬于分代收集器

這些區域的一部分包含新生代,新生代的垃圾收集依然采用暫停所有應用線程的方式,将存活對象拷貝到老年代或者Survivor空間。

這些區域一部分包含老年代,G1收集器通過将對象從一個區域複制到另外一個區域,完成了清理工作。這就意味着,在正常處理過程中,G1完成了堆的壓縮,至少是部分堆的壓縮,這樣也就不會有CMS記憶體碎片化的問題了

垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器

 回收後

垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器

檢視預設的垃圾回收器

jdk8

-XX:+PrintCommandLineFlags -version
           
垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器

Jdk8的預設垃圾收集器

Paraller收集器

-XX:+UseParallelGC

Jdk8如何設定垃圾收集器

垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器

如何選擇垃圾收集器

垃圾收集器回收種類 以及七種垃圾收集器垃圾收集器回收種類 七種垃圾收集器

參考部落格: https://www.cnblogs.com/JRookie/p/11272394.html

繼續閱讀