CMS 垃圾收集器
這兩天在網(wǎng)上看了不少關(guān)于JVM 垃圾回收的相關(guān)知識(shí),大家總結(jié)的都很好,我也從中學(xué)到了很多,現(xiàn)在對(duì)其中的一些內(nèi)容進(jìn)行一下總結(jié)。
這篇文章先總結(jié)一下CMS垃圾回收器,把自己所理解的寫出來,加深認(rèn)識(shí)。
首先CMS 指的是 Concurrent Mark Sweep,并發(fā)標(biāo)記清除。
這里雖然說得是并發(fā),但是并不是整個(gè)過程都是并發(fā)的,在cms中仍然后兩個(gè)階段是需要stw的,只不過它把耗時(shí)的操作放到了并發(fā)的階段中,使stw的時(shí)間很大程度的縮短了。
CMS的階段有
1. 預(yù)標(biāo)記階段 (initial mark) stw
2. 并發(fā)標(biāo)記
3. 并發(fā)預(yù)清理 (需要通過參數(shù)-XX:+CMSParallelRemarkEnabled來開啟)
4. 重標(biāo)記階段 stw
5. 并發(fā)清理階段
6. 重置階段
預(yù)標(biāo)記階段
進(jìn)行可達(dá)性分析,標(biāo)記出GC Root直接飲用的對(duì)象
并發(fā)標(biāo)記
進(jìn)行GC Root tracing,和用戶線程并發(fā)執(zhí)行,由前一階段標(biāo)記處的對(duì)象出發(fā),找出所有的可達(dá)對(duì)象
并發(fā)預(yù)處理
這個(gè)階段可以通過配置來進(jìn)行控制,這個(gè)階段的作用和重標(biāo)記類似,是為了把重標(biāo)記的部分工作放到這里,減少重標(biāo)記階段的停頓時(shí)間。
PS
在進(jìn)行可達(dá)性分析的過程中,可能會(huì)遇到兩種特殊的情況 1.年輕帶中的對(duì)象引用了老年代中的對(duì)象(比較常見)2.老年代中的對(duì)象引用了年輕代中的對(duì)象。
所以在對(duì)老年代進(jìn)行回收的時(shí)候,也要對(duì)年輕代進(jìn)行掃描。所以在這個(gè)操作中為了減少掃描年輕代的時(shí)間,會(huì)先對(duì)年輕代進(jìn)行一次 minor gc(有參數(shù)控制XX:+CMSScavengeBeforeRemark)
在對(duì)年輕代進(jìn)行g(shù)c的時(shí)候,如果也要對(duì)老年代進(jìn)行掃描的話,那停頓的時(shí)間就會(huì)非常長(zhǎng)了。在這里jvm有一個(gè)CardTable的數(shù)據(jù)結(jié)構(gòu)可以高效的實(shí)現(xiàn)這種操作。
為了支持高頻率的新生代的回收,虛擬機(jī)使用一種叫做卡表(Card Table)的數(shù)據(jù)結(jié)構(gòu),卡表作為一個(gè)比特位的集合,每一個(gè)比特位可以用來表示年老代的某一區(qū)域中的所有對(duì)象是否持有新生代對(duì)象的引用。
這樣新生代在GC時(shí),可以不用花大量的時(shí)間掃描所有年老代對(duì)象,來確定每一個(gè)對(duì)象的引用關(guān)系,而可以先掃描卡表,只有卡表的標(biāo)記位為1時(shí),才需要掃描給定區(qū)域的年老代對(duì)象。而卡表位為0的所在區(qū)域的年老代對(duì)象,一定不包含有對(duì)新生代的引用。
所以在進(jìn)行老年代gc的時(shí)候通常也會(huì)進(jìn)行minor gc