JVM垃圾收集(三)垃圾收集器

先來看看目前主流的垃圾收集器和他們的關係


介紹兩個術語的區別

並行:多個垃圾收集線程並行工作,但此時用戶線程仍處於工作狀態

併發:用戶線程與垃圾收集器線程同時執行(可能交替執行),用於線程仍在工作,垃圾收集程序運行於另一個CPU上。

1Serial收集器

Serial收集器是最基本,發展歷史最久的收集器,在早期的版本中,它是唯一的垃圾收集器。這是一個單線程收集器,“單線程”的意義不僅僅在於它只使用一個CPU或一條收集線程去收集垃圾,更重要的是在垃圾收集時,它將暫停其他所有的線程(Stop The World),直到它的收集結束。下圖是Serial/Serail Old收集器的工作流程。對於新生代來說,將使用複製算法進行收集,對於老年代來說,將使用標記-整理算法進行收集


Serial收集器看上去會因爲Stop TheWorld而造成用戶體驗很不好,實際上它依然是Client模式下的主要收集器。因爲它簡單而高效,對於限定單CPU的環境來說,Serial收集器由於沒有其他線程交互的開銷,專心做垃圾收集自然可以獲得最高的單線程收集效率。在桌面應用場景中,收集幾十兆到上百兆的新生代垃圾僅僅會暫停線程幾十到一百多毫秒,只要不頻繁發生,這種停頓是可以接受的。

2 ParNew收集器

ParNew收集器就是Serial收集器的多線程版本,除了使用多線程進行垃圾收集之外,其餘行爲包括Serial收集器可用的所有控制參數、收集算法、StopTheWorld、對象分配規則、回收策略等於Serial收集器完全一致。它的工作過程如下圖所示


PerNew收集器除了多線程之外,與其他的收集器相比沒有什麼創新之處,但他卻是Server模式下虛擬機首選的新生代收集器,其中一個原因就是除了Serail收集器外,目前只有它能與CMS配合。

3 ParallelScavenge 收集器

這個收集器也是面向新生代的收集器,而且採用複製算法的多線程收集器,它與其他幾個的區別在於它不是在儘可能縮短線程停頓時間,它的目標是達到一個可控制的吞吐量

吞吐量的含義是CPU用於用戶代碼時間與CPU消耗的時間的比值,即吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間),虛擬機運行了100分鐘,垃圾收集花掉了1分鐘,那吞吐量就是99%。

Parallel Scavenge收集器提供了兩個參數用於精確控制吞吐量 分別是控制最大垃圾收集停頓時間的-XX:MaxGCPauseMillis參數以及直接設置吞吐量大小的–XX:GCTimeRatio參數。

  • MaxGCPauseMillis參數允許的值是一個大於0的毫秒數,收集器將可能的保證內存回收花費的時間不大於這個值。不過這個數值並不是越少越好,因爲系統縮短收集時間是以犧牲吞吐量作爲前提的。如果這個值很小,系統就會把新生代調小一些,比如收集300MB內存肯定比收集500MB內存要快,但是這樣的話垃圾收集將更加頻繁,原來10秒收集一次,每次停頓100毫秒,現在5秒收集一次,每次停頓70毫秒,吞吐量自然下降了很多。
  • GCTimeRatio參數的值是一個大於0小於100的整數,也就是垃圾收集佔用的時間比率,它是吞吐量的倒數。如果設置爲9,那就運行最大GC時間佔用總時間的10% (1/1+9),這個值默認是99,即1%。

4 SerialOld收集器

他是Serial 收集器的老年代版本,它同樣是一個單線程收集器,使用“標記整理算法”。這個收集器主要給Client模式下虛擬機使用,如果在Sever模式下,它也有兩個用途,一個用途是在JDK1.5版本以前與Parallel Scavenge收集器搭配使用,另一個是作爲CMS的備案,在併發收集 Concurrent Mode Failure時使用。

5  Parallel Old 收集器

Parallel Old是Parallel Scavenge的老年代版本,使用多線程“標記-整理”算法,這個收集器開始於JDK1.6版本,它的出現使得Parallel收集器組合真正的完成。在注重吞吐量已經CPU資源敏感的場合,都優先考慮Parallel Scavenge和Parallel Old組合收集器。工作狀態圖:

6 CMS收集器

CMS(concurrent mark sweep)收集器是一種以獲取最短停頓時間爲目標的收集器。特別對於web應用來說,這個性能尤爲重要。系統停頓時間越短,用戶獲得的體驗就越好。CMS收集器是基於標記-清除算法的,它的實現需要四個步驟

  • 初始標記(CMS initial mark)
  • 併發標記(CMS concurrent map)
  • 重複標記 (CMS remark)
  • 併發清除 (CMS concurrent sweep)

其中,初始標記、重新標記這個兩個步驟依然需要“Stop the world”。初始化標記僅僅是標記一下GCRoots能直接關聯到的對象,速度很快,併發標記階段就是進行GCRootsTracing的過程,而重新標記是在尋找併發標記期間因用戶動作而導致標記產生變動的那一部分記錄,這個停頓要比初始標記長一些,但遠比並發標記的時間短。而整個過程耗時最長的併發標記和併發清除兩個過程都是收集器線程與用戶線程一起工作的,所以從總體上來講,CMS收集器的內存回收過程是與用戶線程一起併發執行的。

看上去CMS挺好,似乎解決了GC停頓時間過長的問題,然而它也存在如下問題:

CMS收集器對CPU資源十分敏感,在併發階段,會因爲它的存在導致用戶的線程資源被佔用,總吞吐量被降低。

CMS無法收集浮動垃圾,所謂浮動垃圾就是併發清除階段用戶的活動產生的垃圾,他們沒有被標記也就無法被清除,只能等待下一次GC。

還有一個缺點就是CMS採用的標記-清除的算法,這種算法會導致產生很多不連續的內存碎片,往往老年代中還有很多空間,但是卻不得不提前觸發一次FullGC。爲了解決這個問題,CMS收集器提供了一個-XX:+UseCMSCompactAtFullCollection開關參數,用於在CMS收集器要進行FullGC時開啓內存碎片合併整理過程,內存整理的過程是無法併發的,因此停頓時間會增加;對於這話情況,虛擬機設計者提供了另外一個參數:-XX:CMSFullGCsBeforeCompaction,這個參數指定了執行多少次不帶壓縮的FullGC後,執行一次帶壓縮的。

7 G1收集器

G1收集器在JDK1.7版本以後被正式啓用,它是一款面向服務端應用的垃圾收集器,它的目的是在未來的版本中取代CMS收集器。

Garbage first垃圾收集器是目前垃圾收集器理論發展的最前沿成果,相比與CMS收集器,G1收集器兩個最突出的改進是:

a.基於標記-整理算法,不產生內存碎片。

b.可以非常精確控制停頓時間,在不犧牲吞吐量前提下,實現低停頓垃圾回收。

G1收集器避免全區域垃圾收集,它把堆內存劃分爲大小固定的幾個獨立區域,並且跟蹤這些區域的垃圾收集進度,同時在後臺維護一個優先級列表,每次根據所允許的收集時間,優先回收垃圾最多的區域,這也是它爲什麼叫garbage first的原因

區域劃分和優先級區域回收機制,確保G1收集器可以在有限時間獲得最高的垃圾收集效率。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章