JVM(HotSpot) 垃圾收集器

需要提前了解的知識:

  1. JVM內(nèi)存模型
  2. JVM垃圾回收算法

HotSpot虛擬機所有的垃圾收集器如下圖:

HotSpot 所有垃圾收集器

上面有7種收集器,分為部分,上面為新生代收集器,下面是老年代收集器。如果兩個收集器之間存在連線,就說明它們可以搭配使用。

新生代的收集器使用復制算法,
老年代使用并發(fā)標記清除(CMS)或標記-整理算法。

Stop The World

Java中Stop-The-World機制簡稱STW,是在執(zhí)行垃圾收集算法時,Java應(yīng)用程序的其他所有線程都被掛起(除了垃圾收集幫助器之外)。Java中一種全局暫?,F(xiàn)象,全局停頓,所有Java代碼停止,native代碼可以執(zhí)行,但不能與JVM交互。

垃圾收集器

序號 收集器 收集范圍 算法 執(zhí)行類型
1 Serial 新生代 復制 單線程
2 ParNew 新生代 復制 多線程并行
3 Parallel 新生代 復制 多線程并行
4 Serial Old 老年代 標記整理 單線程
5 CMS 老年代 標記清除 多線程并發(fā)
6 Parallel Old 老年代 標記整理 多線程
7 G1 全部 復制算法,標記-整理 多線程

解釋:
并行(Parallel):多條垃圾收集線程并行工作,而用戶線程仍處于等待狀態(tài)
并發(fā)(Concurrent):垃圾收集線程與用戶線程一段時間內(nèi)同時工作(交替執(zhí)行)

1、Serial(串行GC)收集器

Serial收集器是一個新生代收集器,單線程執(zhí)行,使用復制算法。它在進行垃圾收集時,必 須暫停其他所有的工作線程(用戶線程)。是Jvm client模式下默認的新生代收集器。對于限定單個CPU的環(huán)境來說,Serial收集器由于沒有線程交互的開銷,專心做垃圾收集自然可以獲得最高的單 線程收集效率。


圖1

2、ParNew(并行GC)收集器

ParNew收集器其實就是serial收集器的多線程版本,除了使用多條線程進行垃圾收集之外,其余行為與Serial收集器一樣。


圖2

3、Parallel Scavenge(并行回收GC)收集器

Parallel Scavenge收集器也是一個新生代收集器,它也是使用復制算法的收集器,又是并行多線程收集器。parallel Scavenge收集器的目標則是達到一個可控制的吞吐量。吞吐量= 程序運行時間/(程序運行時間 + 垃圾收集時間),虛擬機總共運行了100分鐘。其中垃圾收集花掉1分鐘,那吞吐量就是99%。

使用如下2個參數(shù)進行控制吞吐量

  1. -XX:MaxGCPauseMillis
    MaxGCPauseMillis參數(shù)允許的值是一個大于0的毫秒數(shù),收集器將盡力保證內(nèi)存回收花費的時間不超過設(shè)定值。
  2. -XX:GCTimeRatio
    GCTimeRatio參數(shù)的值應(yīng)當是一個大于0小于100的整數(shù),也就是垃圾收集時間占總時間的比率,相當于是吞吐量的倒數(shù)。如果把此參數(shù)設(shè)置為19,那允許的最大GC時間就占總時間的5%(即1 /(1+19)),默認值為99,就是允許最大1%(即1 /(1+99))的垃圾收集時間。

示意圖和ParNew類似(參見圖2)。

4、Serial Old(串行GC)收集器

Serial Old是Serial收集器的老年代版本,它同樣使用一個單線程執(zhí)行收集,使用“標記-整理”算法。主要使用在Client模式下的虛擬機。如果在Server模式下,它主要還有兩大用途:一個是在JDK 1.5及之前的版本中與Parallel Scavenge收集器搭配使用,另外一個就是作為CMS收集器的后備預案。如果CMS收集器出現(xiàn)Concurrent Mode Failure,則Serial Old收集器將作為后備收集器。

詳見圖1 老年的收集

5、Parallel Old(并行GC)收集器

Parallel Old是Parallel Scavenge收集器的老年代版本,使用多線程和“標記-整理”算法。


圖3

6、CMS(并發(fā)GC)收集器

CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器。CMS收集器是基于“標記-清除”算法實現(xiàn)的,整個收集過程大致分為4個步驟:

  1. 初始標記(CMS initial mark)
  2. 并發(fā)標記(CMS concurrenr mark)
  3. 重新標記(CMS remark)
  4. 并發(fā)清除(CMS concurrent sweep)

其中初始標記、重新標記這兩個步驟任然需要停頓其他用戶線程。初始標記僅僅只是標記出GC ROOTS能直接關(guān)聯(lián)到的對象,速度很快,并發(fā)標記階段是進行GC ROOTS 根搜索算法階段,會判定對象是否存活。而重新標記階段則是為了修正并發(fā)標記期間,因用戶程序繼續(xù)運行而導致標記產(chǎn)生變動的那一部分對象的標記記錄,這個階段的停頓時間會被初始標記階段稍長,但比并發(fā)標記階段要短。

由于整個過程中耗時最長的并發(fā)標記和并發(fā)清除過程中,收集器線程都可以與用戶線程一起工作,所以整體來說,CMS收集器的內(nèi)存回收過程是與用戶線程一起并發(fā)執(zhí)行的。

CMS收集器的優(yōu)點:并發(fā)收集、低停頓,但是CMS還遠遠達不到完美,器主要有三個顯著缺點:

  1. CMS收集器對CPU資源非常敏感。
    在并發(fā)階段,雖然不會導致用戶線程停頓,但是會占用CPU資源而導致引用程序變慢,總吞吐量下降。CMS默認啟動的回收線程數(shù)是:(CPU數(shù)量+3)/4。(建議CPU個數(shù)最少4個)。

  2. 無法處理浮動垃圾
    在做垃圾回收的過程中會產(chǎn)生新的垃圾(并行執(zhí)行),所以需要預留一部分空間給用戶線程使用。
    可以使用-XX:CMSInitiatingOccupancyFraction(jdk1.6 默認為92%)參數(shù)來設(shè)置,預留多少空間開始做GC。如果在垃圾回收的過程中,剩余空間不足仍然滿足不了用戶線程生成對象所需要的空間,就會出現(xiàn)“Concurrent Mode Failure”失敗,這時候虛擬機將啟動后備預案:臨時啟用Serial Old收集器來重新進行老年代的垃圾收集,這樣停頓時間就很長了。

  3. CMS是基于“標記-清除”算法實現(xiàn)的收集器,使用“標記-清除”算法收集后,會產(chǎn)生大量碎片。
    空間碎片太多時,將會給對象分配帶來很多麻煩,比如說大對象,內(nèi)存空間找不到連續(xù)的空間來分配不得不提前觸發(fā)一次Full GC。為了解決這個問題,CMS收集器提供了一個-XX:UseCMSCompactAtFullCollection開關(guān)參數(shù),用于在Full GC之后增加一個碎片整理過程,還可通過-XX:CMSFullGCBeforeCompaction參數(shù)設(shè)置執(zhí)行多少次不壓縮的Full GC之后,跟著來一次碎片整理過程。


    圖4

7、G1收集器
G1(Garbage First)垃圾回收器是用在heap memory很大的情況下,把heap劃分為很多很多的region塊,然后并行的對其進行垃圾回收。
G1垃圾回收器在清除實例所占用的內(nèi)存空間后,還會做內(nèi)存壓縮。
G1垃圾回收器回收region的時候基本不會STW,而是基于 most garbage優(yōu)先回收 的策略來對region進行垃圾回收的。

結(jié)果如下圖:


圖5

一個region有可能屬于Eden,Survivor或者Tenured內(nèi)存區(qū)域。圖中的E表示該region屬于Eden內(nèi)存區(qū)域,S表示屬于Survivor內(nèi)存區(qū)域,T表示屬于Tenured內(nèi)存區(qū)域。圖中空白的表示未使用的內(nèi)存空間。G1垃圾收集器還增加了一種新的內(nèi)存區(qū)域,叫做Humongous內(nèi)存區(qū)域,如圖中的H塊。這種內(nèi)存區(qū)域主要用于存儲大對象-即大小超過一個region大小的50%的對象。

年輕代垃圾收集

在G1垃圾收集器中,年輕代的垃圾回收過程使用復制算法。把Eden區(qū)和Survivor區(qū)的對象復制到新的Survivor區(qū)域。
如下圖:


圖6

老年代垃收集

對于年老代上的垃圾收集,G1垃圾收集器也分為4個階段,基本跟CMS垃圾收集器一樣,但略有不同:

Initial Mark階段 - 同CMS垃圾收集器的Initial Mark階段一樣,G1也需要暫停應(yīng)用程序的執(zhí)行,它會標記從根對象出發(fā),在根對象的第一層孩子節(jié)點中標記所有可達的對象。但是G1的垃圾收集器的Initial Mark階段是跟minor gc一同發(fā)生的。也就是說,在G1中,你不用像在CMS那樣,單獨暫停應(yīng)用程序的執(zhí)行來運行Initial Mark階段,而是在G1觸發(fā)minor gc的時候一并將年老代上的Initial Mark給做了。

Concurrent Mark階段 - 在這個階段G1做的事情跟CMS一樣。但G1同時還多做了一件事情,就是如果在Concurrent Mark階段中,發(fā)現(xiàn)哪些Tenured region中對象的存活率很小或者基本沒有對象存活,那么G1就會在這個階段將其回收掉,而不用等到后面的clean up階段。這也是Garbage First名字的由來。同時,在該階段,G1會計算每個 region的對象存活率,方便后面的clean up階段使用 。

Remark階段 - 在這個階段G1做的事情跟CMS一樣, 但是采用的算法不同,G1采用一種叫做SATB(snapshot-at-the-begining)的算法能夠在Remark階段更快的標記可達對象。

Clean up/Copy階段 - 在G1中,沒有CMS中對應(yīng)的Sweep階段。相反 它有一個Clean up/Copy階段,在這個階段中,G1會挑選出那些對象存活率低的region進行回收,這個階段也是和minor gc一同發(fā)生的,如下圖所示:

圖7

想了解更多精彩內(nèi)容請關(guān)注我的公眾號

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容