九神帶你入門(mén)JVM(下)

我們接著上面一篇繼續(xù)學(xué)習(xí)JVM的基本知識(shí)找颓。

對(duì)象存活判斷

上篇中我們介紹過(guò)JVM垃圾回收綜述中說(shuō)過(guò)一次垃圾回收之后會(huì)有一些對(duì)象存活谈截。這節(jié)我們介紹兩個(gè)判斷對(duì)象存活的算法嵌施。

判斷對(duì)象存活有引用計(jì)數(shù)算法和可達(dá)性分析算法腿箩。

1挣磨、引用計(jì)數(shù)算法

給每一個(gè)對(duì)象添加一個(gè)引用計(jì)數(shù)器雇逞,每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器值加1茁裙;每當(dāng)有一個(gè)地方不再引用它時(shí)塘砸,計(jì)數(shù)器值減1,這樣只要計(jì)數(shù)器的值不為0晤锥,就說(shuō)明還有地方引用它谣蠢,它就不是無(wú)用的對(duì)象。

這種方法看起來(lái)非常簡(jiǎn)單,但目前許多主流的虛擬機(jī)都沒(méi)有選用這種算法來(lái)管理內(nèi)存眉踱,原因就是當(dāng)某些對(duì)象之間互相引用時(shí)挤忙,無(wú)法判斷出這些對(duì)象是否已死。如下圖谈喳,對(duì)象1和對(duì)象2都沒(méi)有被堆外的變量引用册烈,而是被對(duì)方互相引用,這時(shí)他們雖然沒(méi)有用處了婿禽,但是引用計(jì)數(shù)器的值仍然是1赏僧,無(wú)法判斷他們是死對(duì)象,垃圾回收器也就無(wú)法回收扭倾。

img

2淀零、可達(dá)性分析算法

了解可達(dá)性分析算法之前先了解一個(gè)概念——GC Roots,垃圾收集的起點(diǎn)膛壹,可以作為GC Roots的有虛擬機(jī)棧中本地變量表中引用的對(duì)象驾中、方法區(qū)中靜態(tài)屬性引用的對(duì)象、方法區(qū)中常量引用的對(duì)象模聋、本地方法棧中JNI(Native方法)引用的對(duì)象肩民。 當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連(GC Roots到這個(gè)對(duì)象不可達(dá))時(shí),就說(shuō)明此對(duì)象是不可用的链方,是死對(duì)象持痰。如下圖:object1、object2祟蚀、object3工窍、object4和GC Roots之間有可達(dá)路徑,這些對(duì)象不會(huì)被回收前酿,但object5患雏、object6、object7到GC Roots之間沒(méi)有可達(dá)路徑薪者,這些對(duì)象就是死對(duì)象纵苛。

img

上面被判定為非存活的死對(duì)象(object5、object6言津、object7)并不是必死無(wú)疑攻人,還有挽救的余地。進(jìn)行可達(dá)性分析后對(duì)象和GC Roots之間沒(méi)有引用鏈相連時(shí)悬槽,對(duì)象將會(huì)被進(jìn)行一次標(biāo)記怀吻,接著會(huì)判斷如果對(duì)象沒(méi)有覆蓋Object的finalize()方法或者finalize()方法已經(jīng)被虛擬機(jī)調(diào)用過(guò),那么它們就會(huì)清除初婆;如果對(duì)象覆蓋了finalize()方法且還沒(méi)有被調(diào)用蓬坡,則會(huì)執(zhí)行finalize()方法中的內(nèi)容猿棉,所以在finalize()方法中如果重新與GC Roots引用鏈上的對(duì)象關(guān)聯(lián)就可以拯救自己。當(dāng)然屑咳,實(shí)際中一般不會(huì)這么做萨赁。

GC算法

接下來(lái)講GC的算法,主要有標(biāo)記-清除算法兆龙、復(fù)制算法杖爽、標(biāo)記-整理算法、分代收集算法紫皇。

1慰安、標(biāo)記-清除算法

最基礎(chǔ)的收集算法是“標(biāo)記-清除”(Mark-Sweep)算法,分兩個(gè)階段:首先標(biāo)記出所有需要回收的對(duì)象聪铺,在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象化焕。

優(yōu)點(diǎn):不需要進(jìn)行對(duì)象的移動(dòng),并且僅對(duì)不存活的對(duì)象進(jìn)行處理铃剔,在存活對(duì)象比較多的情況極為有效撒桨。

不足:一個(gè)是效率問(wèn)題,標(biāo)記和清除兩個(gè)過(guò)程的效率都不高番宁;另一個(gè)是空間問(wèn)題元莫,標(biāo)記清除之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片赖阻,空間碎片太多可能導(dǎo)致以后在程序運(yùn)行過(guò)程需要分配較大對(duì)象時(shí)蝶押,無(wú)法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一個(gè)的垃圾收集動(dòng)作。

下面兩張圖從兩個(gè)角度闡明了標(biāo)記-清楚算法:

img
img

2火欧、復(fù)制算法

為了解決效率問(wèn)題棋电,一種稱為復(fù)制(Copying)的收集算法出現(xiàn)了,它將可用內(nèi)存按容量劃分為大小相等的兩塊苇侵,每次只使用其中的一塊赶盔。當(dāng)這一塊內(nèi)存用完了,就將還存活著的對(duì)象復(fù)制到另外一塊上榆浓,然后再把已經(jīng)使用過(guò)的內(nèi)存空間一次清理掉于未。這樣使得每次都是對(duì)整個(gè)半?yún)^(qū)進(jìn)行內(nèi)存回收,內(nèi)存分配時(shí)也就不用考慮內(nèi)存碎片等復(fù)雜情況陡鹃,只要移動(dòng)堆頂指針烘浦,按順序分配內(nèi)存即可,實(shí)現(xiàn)簡(jiǎn)單萍鲸,運(yùn)行高效闷叉。代價(jià)是內(nèi)存縮小為原來(lái)的一半。

復(fù)制算法過(guò)程如下面兩張圖表示:

img
img

商業(yè)虛擬機(jī)用這個(gè)回收算法來(lái)回收新生代脊阴。IBM研究表明98%的對(duì)象是“朝生夕死“握侧,不需要按照1-1的比例來(lái)劃分內(nèi)存空間蚯瞧,而是將內(nèi)存分為一塊較大的”Eden“空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor品擎。當(dāng)回收時(shí)埋合,將Eden和Survivor中還存活的對(duì)象一次性復(fù)制到另外一個(gè)Survivor空間上,最后清理掉Eden和剛才用過(guò)的Survivor空間萄传。Hotspot虛擬機(jī)默認(rèn)Eden和Survivor的比例是8-1.即每次可用整個(gè)新生代的90%, 只有一個(gè)survivor饥悴,即1/10被”浪費(fèi)“。當(dāng)然盲再,98%的對(duì)象回收只是一般場(chǎng)景下的數(shù)據(jù)西设,我們沒(méi)有辦法保證每次回收都只有不多于10%的對(duì)象存活,當(dāng)Survivor空間不夠時(shí)答朋,需要依賴其他內(nèi)存(老年代)進(jìn)行分配擔(dān)保(Handle Promotion).

如果另外一塊survivor空間沒(méi)有足夠空間存放上一次新生代收集下來(lái)的存活對(duì)象時(shí)贷揽,這些對(duì)象將直接通過(guò)分配擔(dān)保機(jī)制進(jìn)入老年代。

下面大概介紹一下這個(gè)eden survivor復(fù)制的過(guò)程梦碗。

Eden Space字面意思是伊甸園禽绪,對(duì)象被創(chuàng)建的時(shí)候首先放到這個(gè)區(qū)域,進(jìn)行垃圾回收后洪规,不能被回收的對(duì)象被放入到空的survivor區(qū)域印屁。

Survivor Space幸存者區(qū),用于保存在eden space內(nèi)存區(qū)域中經(jīng)過(guò)垃圾回收后沒(méi)有被回收的對(duì)象斩例。Survivor有兩個(gè)雄人,分別為T(mén)o Survivor、 From Survivor念赶,這個(gè)兩個(gè)區(qū)域的空間大小是一樣的础钠。執(zhí)行垃圾回收的時(shí)候Eden區(qū)域不能被回收的對(duì)象被放入到空的survivor(也就是To Survivor,同時(shí)Eden區(qū)域的內(nèi)存會(huì)在垃圾回收的過(guò)程中全部釋放)叉谜,另一個(gè)survivor(即From Survivor)里不能被回收的對(duì)象也會(huì)被放入這個(gè)survivor(即To Survivor)旗吁,然后To Survivor 和 From Survivor的標(biāo)記會(huì)互換,始終保證一個(gè)survivor是空的停局。

為啥需要兩個(gè)survivor很钓?因?yàn)樾枰粋€(gè)完整的空間來(lái)復(fù)制過(guò)來(lái)。當(dāng)滿的時(shí)候晉升董栽。每次都往標(biāo)記為to的里面放码倦,然后互換,這時(shí)from已經(jīng)被清空裆泳,可以當(dāng)作to了叹洲。

3、標(biāo)記-整理算法

復(fù)制收集算法在對(duì)象成活率較高時(shí)就要進(jìn)行較多的復(fù)制操作工禾,效率將會(huì)變低运提。更關(guān)鍵的是蝗柔,如果不想浪費(fèi)50%的空間,就需要有額外的空間進(jìn)行分配擔(dān)保民泵,以應(yīng)對(duì)被使用的內(nèi)存中所有對(duì)象都100%存活的極端情況癣丧,所以,老年代一般不能直接選用這種算法栈妆。

根據(jù)老年代的特點(diǎn)胁编,有人提出一種”標(biāo)記-整理“Mark-Compact算法,標(biāo)記過(guò)程仍然和標(biāo)記-清除一樣鳞尔,但后續(xù)步驟不是直接對(duì)可回收對(duì)象進(jìn)行清理嬉橙,而是讓所有存活的對(duì)象都向一端移動(dòng),然后直接清理端邊界以外的內(nèi)存寥假。

下面兩張圖講了這個(gè)算法的過(guò)程:

img
img

4市框、分代收集算法

當(dāng)前商業(yè)虛擬機(jī)的垃圾收集都采用”分代收集“(Generational Collection)算法,這種算法根據(jù)對(duì)象存活周期的不同將內(nèi)存劃分為幾塊糕韧。一般把Java堆分為新生代和老年代枫振,這樣就可以根據(jù)各個(gè)年代的特點(diǎn)采用最適當(dāng)?shù)氖占惴āT谛律┎剩看卫占瘯r(shí)都發(fā)現(xiàn)大批對(duì)象死去粪滤,只有少量存活,那就選用復(fù)制算法雀扶,只需要付出少量存活對(duì)象的復(fù)制成本就可以完成收集杖小。而老年代中因?yàn)閷?duì)象存活率較高,沒(méi)有額外的空間對(duì)它進(jìn)行分配擔(dān)保怕吴,就必須使用”標(biāo)記-清理“和”標(biāo)記-整理“算法來(lái)進(jìn)行回收窍侧。

這種算法就是我們?cè)谇懊鍶VM垃圾回收綜述中講述的內(nèi)容县踢。其本質(zhì)是更為靈活的使用”標(biāo)記-清理“和”標(biāo)記-整理“算法转绷。

常見(jiàn)的GC回收器

現(xiàn)在常見(jiàn)的垃圾收集器有如下幾種

新生代收集器:Serial、ParNew硼啤、Parallel Scavenge

老年代收集器:Serial Old议经、CMS、Parallel Old

堆內(nèi)存垃圾收集器:G1

如圖所示:

img

0谴返、垃圾收集時(shí)間

當(dāng)程序運(yùn)行時(shí)煞肾,各種數(shù)據(jù)、對(duì)象嗓袱、線程籍救、內(nèi)存等都時(shí)刻在發(fā)生變化,當(dāng)下達(dá)垃圾收集命令后垃圾收集器并不會(huì)立刻執(zhí)行垃圾收集渠抹。為了搞明白垃圾收集器的工作原理蝙昙,我們需要講兩個(gè)名詞:安全點(diǎn)(safepoint)和安全區(qū)(safe region)闪萄。

安全點(diǎn):從線程角度看,安全點(diǎn)可以理解為是在代碼執(zhí)行過(guò)程中的一些特殊位置奇颠,當(dāng)線程執(zhí)行到安全點(diǎn)的時(shí)候败去,說(shuō)明虛擬機(jī)當(dāng)前的狀態(tài)是安全的,如果有需要烈拒,可以在這里暫停用戶線程圆裕。當(dāng)垃圾收集時(shí),如果需要暫停當(dāng)前的用戶線程荆几,但用戶線程當(dāng)時(shí)沒(méi)在安全點(diǎn)上吓妆,則應(yīng)該等待這些線程執(zhí)行到安全點(diǎn)再暫停。

安全區(qū):安全點(diǎn)是相對(duì)于運(yùn)行中的線程來(lái)說(shuō)的吨铸,對(duì)于如sleep或blocked等狀態(tài)的線程耿战,收集器不會(huì)等待這些線程被分配CPU時(shí)間,這時(shí)候只要線程處于安全區(qū)中焊傅,就可以算是安全的剂陡。安全區(qū)就是在一段代碼片段中,引用關(guān)系不會(huì)發(fā)生變化狐胎,可以看作是被擴(kuò)展鸭栖、拉長(zhǎng)了的安全點(diǎn)。

GC過(guò)程一定會(huì)發(fā)生STW(Stop The World)握巢,而一旦發(fā)生STW必然會(huì)影響用戶使用晕鹊,所以GC的發(fā)展都是在圍繞減少STW時(shí)間這一目的。

1暴浦、Serial 收集器

Serial是一款用于新生代的單線程收集器溅话,采用復(fù)制算法進(jìn)行垃圾收集。Serial進(jìn)行垃圾收集時(shí)歌焦,不僅只用一條線程執(zhí)行垃圾收集工作飞几,它在收集的同時(shí),所有的用戶線程必須暫停(Stop The World)独撇。 如下是Serial收集器和Serial Old收集器結(jié)合進(jìn)行垃圾收集的示意圖屑墨,當(dāng)用戶線程都執(zhí)行到安全點(diǎn)時(shí),所有線程暫停執(zhí)行纷铣,Serial收集器以單線程卵史,采用復(fù)制算法進(jìn)行垃圾收集工作,收集完之后搜立,用戶線程繼續(xù)開(kāi)始執(zhí)行以躯。

img

適用場(chǎng)景:Client模式(桌面應(yīng)用);單核服務(wù)器啄踊∮巧瑁可以用-XX:+UserSerialGC來(lái)選擇Serial作為新生代收集器色鸳。

2、ParNew 收集器

ParNew就是一個(gè)Serial的多線程版本见转,其它與Serial并無(wú)區(qū)別命雀。ParNew在單核CPU環(huán)境并不會(huì)比Serial收集器達(dá)到更好的效果,它默認(rèn)開(kāi)啟的收集線程數(shù)和CPU數(shù)量一致斩箫,可以通過(guò)-XX:ParallelGCThreads來(lái)設(shè)置垃圾收集的線程數(shù)吏砂。 如下是ParNew收集器和Serial Old收集器結(jié)合進(jìn)行垃圾收集的示意圖,當(dāng)用戶線程都執(zhí)行到安全點(diǎn)時(shí)乘客,所有線程暫停執(zhí)行狐血,ParNew收集器以多線程,采用復(fù)制算法進(jìn)行垃圾收集工作易核,收集完之后匈织,用戶線程繼續(xù)開(kāi)始執(zhí)行。

img

適用場(chǎng)景:多核服務(wù)器牡直;與CMS收集器搭配使用缀匕。當(dāng)使用-XX:+UserConcMarkSweepGC來(lái)選擇CMS作為老年代收集器時(shí),新生代收集器默認(rèn)就是ParNew碰逸,也可以用-XX:+UseParNewGC來(lái)指定使用ParNew作為新生代收集器乡小。

3、Parallel Scavenge 收集器

Parallel Scavenge也是一款用于新生代的多線程收集器饵史,與ParNew的不同之處是满钟,ParNew的目標(biāo)是盡可能縮短垃圾收集時(shí)用戶線程的停頓時(shí)間,Parallel Scavenge的目標(biāo)是達(dá)到一個(gè)可控制的吞吐量胳喷。吞吐量就是CPU執(zhí)行用戶線程的的時(shí)間與CPU執(zhí)行總時(shí)間的比值【吞吐量=運(yùn)行用戶代代碼時(shí)間/(運(yùn)行用戶代碼時(shí)間+垃圾收集時(shí)間)】湃番,比如虛擬機(jī)一共運(yùn)行了100分鐘,其中垃圾收集花費(fèi)了1分鐘吭露,那吞吐量就是99% 吠撮。比如下面兩個(gè)場(chǎng)景,垃圾收集器每100秒收集一次奴饮,每次停頓10秒纬向,和垃圾收集器每50秒收集一次,每次停頓時(shí)間7秒戴卜,雖然后者每次停頓時(shí)間變短了,但是總體吞吐量變低了琢岩,CPU總體利用率變低了投剥。

收集頻率 每次停頓時(shí)間 吞吐量
每100秒收集一次 10秒 91%
每50秒收集一次 7秒 88%

可以通過(guò)-XX:MaxGCPauseMillis來(lái)設(shè)置收集器盡可能在多長(zhǎng)時(shí)間內(nèi)完成內(nèi)存回收,可以通過(guò)-XX:GCTimeRatio來(lái)精確控制吞吐量担孔。

如下是Parallel收集器和Parallel Old收集器結(jié)合進(jìn)行垃圾收集的示意圖江锨,在新生代吃警,當(dāng)用戶線程都執(zhí)行到安全點(diǎn)時(shí),所有線程暫停執(zhí)行啄育,ParNew收集器以多線程酌心,采用復(fù)制算法進(jìn)行垃圾收集工作,收集完之后挑豌,用戶線程繼續(xù)開(kāi)始執(zhí)行安券;在老年代,當(dāng)用戶線程都執(zhí)行到安全點(diǎn)時(shí)氓英,所有線程暫停執(zhí)行侯勉,Parallel Old收集器以多線程,采用標(biāo)記整理算法進(jìn)行垃圾收集工作铝阐。

img

適用場(chǎng)景:注重吞吐量址貌,高效利用CPU,需要高效運(yùn)算且不需要太多交互徘键×范裕可以使用-XX:+UseParallelGC來(lái)選擇Parallel Scavenge作為新生代收集器,jdk7吹害、jdk8默認(rèn)使用Parallel Scavenge作為新生代收集器锹淌。

4、Serial Old收集器

Serial Old收集器是Serial的老年代版本赠制,同樣是一個(gè)單線程收集器赂摆,采用標(biāo)記-整理算法。

如下圖是Serial收集器和Serial Old收集器結(jié)合進(jìn)行垃圾收集的示意圖:

img

適用場(chǎng)景:Client模式(桌面應(yīng)用)钟些;單核服務(wù)器烟号;與Parallel Scavenge收集器搭配;作為CMS收集器的后備預(yù)案政恍。

5汪拥、CMS(Concurrent Mark Sweep) 收集器

CMS收集器是一種以最短回收停頓時(shí)間為目標(biāo)的收集器,以“最短用戶線程停頓時(shí)間”著稱篙耗。整個(gè)垃圾收集過(guò)程分為4個(gè)步驟:

  1. 初始標(biāo)記:標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象迫筑,速度較快

  2. 并發(fā)標(biāo)記:進(jìn)行GC Roots Tracing,標(biāo)記出全部的垃圾對(duì)象宗弯,耗時(shí)較長(zhǎng)

  3. 重新標(biāo)記:修正并發(fā)標(biāo)記階段引用戶程序繼續(xù)運(yùn)行而導(dǎo)致變化的對(duì)象的標(biāo)記記錄脯燃,耗時(shí)較短

  4. 并發(fā)清除:用標(biāo)記-清除算法清除垃圾對(duì)象,耗時(shí)較長(zhǎng)

整個(gè)過(guò)程耗時(shí)最長(zhǎng)的并發(fā)標(biāo)記和并發(fā)清除都是和用戶線程一起工作蒙保,所以從總體上來(lái)說(shuō)辕棚,CMS收集器垃圾收集可以看做是和用戶線程并發(fā)執(zhí)行的。

img

CMS收集器也存在一些缺點(diǎn):

  • 對(duì)CPU資源敏感:默認(rèn)分配的垃圾收集線程數(shù)為(CPU數(shù)+3)/4,隨著CPU數(shù)量下降逝嚎,占用CPU資源越多扁瓢,吞吐量越小

  • 無(wú)法處理浮動(dòng)垃圾:在并發(fā)清理階段,由于用戶線程還在運(yùn)行补君,還會(huì)不斷產(chǎn)生新的垃圾引几,CMS收集器無(wú)法在當(dāng)次收集中清除這部分垃圾。同時(shí)由于在垃圾收集階段用戶線程也在并發(fā)執(zhí)行挽铁,CMS收集器不能像其他收集器那樣等老年代被填滿時(shí)再進(jìn)行收集伟桅,需要預(yù)留一部分空間提供用戶線程運(yùn)行使用。當(dāng)CMS運(yùn)行時(shí)屿储,預(yù)留的內(nèi)存空間無(wú)法滿足用戶線程的需要贿讹,就會(huì)出現(xiàn)“Concurrent Mode Failure”的錯(cuò)誤,這時(shí)將會(huì)啟動(dòng)后備預(yù)案够掠,臨時(shí)用Serial Old來(lái)重新進(jìn)行老年代的垃圾收集民褂。

  • 因?yàn)镃MS是基于標(biāo)記-清除算法,所以垃圾回收后會(huì)產(chǎn)生空間碎片疯潭,可以通過(guò)-XX:UserCMSCompactAtFullCollection開(kāi)啟碎片整理(默認(rèn)開(kāi)啟)赊堪,在CMS進(jìn)行Full GC之前,會(huì)進(jìn)行內(nèi)存碎片的整理竖哩。還可以用-XX:CMSFullGCsBeforeCompaction設(shè)置執(zhí)行多少次不壓縮(不進(jìn)行碎片整理)的Full GC之后哭廉,跟著來(lái)一次帶壓縮(碎片整理)的Full GC。

適用場(chǎng)景:重視服務(wù)器響應(yīng)速度相叁,要求系統(tǒng)停頓時(shí)間最短遵绰。可以使用-XX:+UserConMarkSweepGC來(lái)選擇CMS作為老年代收集器增淹。

6椿访、Parallel Old 收集器

Parallel Old收集器是Parallel Scavenge的老年代版本,是一個(gè)多線程收集器虑润,采用標(biāo)記-整理算法成玫。可以與Parallel Scavenge收集器搭配拳喻,可以充分利用多核CPU的計(jì)算能力哭当。如Parallel Scavenge中的兩個(gè)垃圾收集器的搭配使用圖。

適用場(chǎng)景:與Parallel Scavenge收集器搭配使用冗澈;注重吞吐量钦勘。jdk7、jdk8默認(rèn)使用該收集器作為老年代收集器渗柿,使用 -XX:+UseParallelOldGC來(lái)指定使用Paralle Old收集器个盆。

7脖岛、G1 收集器

上述的一些GC收集器通過(guò)并行與并發(fā)已經(jīng)極大的減少了STW的時(shí)間朵栖,但是STW的時(shí)間還是會(huì)因?yàn)楦鞣N原因不可控颊亮,而G1提供的一個(gè)最大功能就是可控的STW時(shí)間。

G1通過(guò)把Java堆分成大小相等的多個(gè)獨(dú)立區(qū)域陨溅,回收時(shí)計(jì)算出每個(gè)區(qū)域回收所獲得的空間以及所需時(shí)間的經(jīng)驗(yàn)值终惑,根據(jù)記錄兩個(gè)值來(lái)判斷哪個(gè)區(qū)域最具有回收價(jià)值,所以叫Garbage First(垃圾優(yōu)先)门扇。

這里有幾個(gè)重要的概念:

  • Region(區(qū)域):G1采用了分區(qū)(Region)的思路雹有,將整個(gè)堆空間分成若干個(gè)大小相等的內(nèi)存區(qū)域,每次分配對(duì)象空間將逐段地使用內(nèi)存臼寄。因此霸奕,在堆的使用上,G1并不要求對(duì)象的存儲(chǔ)一定是物理上連續(xù)的吉拳,只要邏輯上連續(xù)即可质帅;每個(gè)分區(qū)也不會(huì)確定地為某個(gè)代服務(wù),可以按需在年輕代和老年代之間切換留攒。啟動(dòng)時(shí)可以通過(guò)參數(shù)-XX:G1HeapRegionSize=n可指定分區(qū)大小(1MB~32MB煤惩,且必須是2的冪),默認(rèn)將整堆劃分為2048個(gè)分區(qū)炼邀。

  • Card(卡片):在每個(gè)分區(qū)內(nèi)部又被分成了若干個(gè)大小為512 Byte卡片(Card)魄揉,標(biāo)識(shí)堆內(nèi)存最小可用粒度所有分區(qū)的卡片將會(huì)記錄在全局卡片表(Global Card Table)中,分配的對(duì)象會(huì)占用物理上連續(xù)的若干個(gè)卡片拭宁,當(dāng)查找對(duì)分區(qū)內(nèi)對(duì)象的引用時(shí)便可通過(guò)記錄卡片來(lái)查找該引用對(duì)象(見(jiàn)RSet)洛退。每次對(duì)內(nèi)存的回收,都是對(duì)指定分區(qū)的卡片進(jìn)行處理杰标。

  • CSet(收集集合):GC過(guò)程記錄的可被回收的Region的集合兵怯。在CSet中存活的數(shù)據(jù)會(huì)在GC過(guò)程中被移動(dòng)到另一個(gè)可用分區(qū),CSet中的分區(qū)可以來(lái)自eden空間在旱、survivor空間摇零、或者老年代。

  • RSet(Remembered Set 記憶集合):記錄了其他Region中的對(duì)象引用本Region中對(duì)象的關(guān)系桶蝎,屬于points-into結(jié)構(gòu) (誰(shuí)引用了我的對(duì)象)驻仅。作用是不需要掃描整個(gè)堆找到誰(shuí)引用了當(dāng)前分區(qū)中的對(duì)象,只需要掃描RSet即可登渣。

  • Humongous regions:用來(lái)存放大于標(biāo)準(zhǔn)的Region內(nèi)存50%的大對(duì)象區(qū)域噪服,如果有些對(duì)象大于整個(gè)Region就會(huì)去找連續(xù)的Region保存,如果沒(méi)有就會(huì)觸發(fā)GC胜茧。

G1收集器與之前的收集器最大的不同就在于堆內(nèi)存的劃分粘优,之前的收集器只區(qū)分新生代與老年代仇味,而G1收集器則是把堆內(nèi)存劃分成多個(gè)獨(dú)立的Region。

img

在上圖中G1的Java堆中每個(gè)Region都有一個(gè)身份雹顺,每個(gè)Region有可能是eden丹墨、survivor、old嬉愧,但是他們的身份僅僅是邏輯上的贩挣,是可以變化的,G1可以根據(jù)情況動(dòng)態(tài)的調(diào)整各種Region的數(shù)量没酣,通過(guò)控制回收的Region數(shù)量來(lái)控制STW的時(shí)間王财,以達(dá)到STW時(shí)間的可控制。

雖然G1收集器把Java堆化整為零成一個(gè)個(gè)Region裕便,但是也不會(huì)進(jìn)行所有Region進(jìn)行收集绒净,G1也分成了兩種收集模式,兩種模式如下:

Young GC: CSet就是所有年輕代里面的Region偿衰;

Mixed GC: CSet是所有年輕代里的Region加上在全局并發(fā)標(biāo)記階段標(biāo)記出來(lái)的收益高的老年代Region挂疆;

Young GC過(guò)程:

階段1:根掃描,靜態(tài)和本地對(duì)象被掃描哎垦;

階段2:更新RS囱嫩,處理dirty card隊(duì)列更新RS;

階段3:處理RS漏设,檢測(cè)從年輕代指向老年代的對(duì)象墨闲;

階段4:對(duì)象拷貝,拷貝存活的對(duì)象到survivorl/old區(qū)域郑口;

階段5:處理引用隊(duì)列鸳碧,軟引用,弱引用犬性,虛引用處理瞻离;

Mixed GC過(guò)程:

1、全局并發(fā)標(biāo)記(global concurrent marking)

2乒裆、拷貝存活對(duì)象(evacuation)

全局并發(fā)標(biāo)記包括5個(gè)步驟:

1套利、初始標(biāo)記(initial mark,STW):標(biāo)記了從GCRoot開(kāi)始直接可達(dá)的對(duì)象鹤耍。

2肉迫、根區(qū)域掃描(root region scan):G1 GC 在初始標(biāo)記的存活區(qū)掃描對(duì)老年代的引用,并標(biāo)記被引用的對(duì)象稿黄。該階段與應(yīng)用程序(非 STW)同時(shí)運(yùn)行喊衫,并且只有完成該階段后,才能開(kāi)始下一次 STW 年輕代垃圾回收杆怕。

3族购、并發(fā)標(biāo)記(Concurrent Marking):G1 GC 在整個(gè)堆中查找可訪問(wèn)的(存活的)對(duì)象壳贪。該階段與應(yīng)用程序同時(shí)運(yùn)行,可以被 STW 年輕代垃圾回收中斷寝杖。

4违施、重新標(biāo)記(Remark,STW):該階段是 STW 回收朝墩,幫助完成標(biāo)記周期醉拓。G1 GC 清空 SATB 緩沖區(qū)伟姐,跟蹤未被訪問(wèn)的存活對(duì)象收苏,并執(zhí)行引用處理。

5愤兵、清除垃圾(Cleanup):在這個(gè)最后階段鹿霸,G1 GC 執(zhí)行統(tǒng)計(jì)和 RSet 凈化的 STW 操作。在統(tǒng)計(jì)期間秆乳,G1 GC 會(huì)識(shí)別完全空閑的區(qū)域和可供進(jìn)行混合垃圾回收的區(qū)域懦鼠。清理階段在將空白區(qū)域重置并返回到空閑列表時(shí)為部分并發(fā)。

適用場(chǎng)景:要求盡可能可控GC停頓時(shí)間屹堰;內(nèi)存占用較大的應(yīng)用肛冶。可以用-XX:+UseG1GC使用G1收集器扯键,jdk9默認(rèn)使用G1收集器睦袖。

GC日志

每一種回收器的日志格式都是由其自身的實(shí)現(xiàn)決定的谚殊,換而言之谤专,每種回收器的日志格式都可以不一樣础拨。但虛擬機(jī)設(shè)計(jì)者為了方便用戶閱讀华畏,將各個(gè)回收器的日志都維持一定的共性杠步。

GC日志是學(xué)GC調(diào)優(yōu)之前的必備前置條件伪嫁,所以我們必須學(xué)會(huì)枫慷。下面放兩張網(wǎng)圖周拐,大家可以從中看到日志的每個(gè)節(jié)點(diǎn):

young gc 日志:

img

Full GC日志:

img

文章首發(fā)于:
九神帶你入門(mén)JVM(下)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末爱只,一起剝皮案震驚了整個(gè)濱河市皿淋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌恬试,老刑警劉巖窝趣,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異忘渔,居然都是意外死亡高帖,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)畦粮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)散址,“玉大人乖阵,你說(shuō)我怎么就攤上這事≡铮” “怎么了瞪浸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)吏祸。 經(jīng)常有香客問(wèn)我对蒲,道長(zhǎng),這世上最難降的妖魔是什么贡翘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任蹈矮,我火速辦了婚禮,結(jié)果婚禮上鸣驱,老公的妹妹穿的比我還像新娘泛鸟。我一直安慰自己,他們只是感情好踊东,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布北滥。 她就那樣靜靜地躺著,像睡著了一般闸翅。 火紅的嫁衣襯著肌膚如雪再芋。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,255評(píng)論 1 308
  • 那天坚冀,我揣著相機(jī)與錄音济赎,去河邊找鬼。 笑死遗菠,一個(gè)胖子當(dāng)著我的面吹牛联喘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播辙纬,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼豁遭,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了贺拣?” 一聲冷哼從身側(cè)響起蓖谢,我...
    開(kāi)封第一講書(shū)人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎譬涡,沒(méi)想到半個(gè)月后闪幽,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涡匀,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年盯腌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陨瘩。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡腕够,死狀恐怖级乍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情帚湘,我是刑警寧澤玫荣,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站大诸,受9級(jí)特大地震影響捅厂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜资柔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一焙贷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧建邓,春花似錦盈厘、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)外遇。三九已至注簿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間跳仿,已是汗流浹背诡渴。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留菲语,地道東北人妄辩。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像山上,于是被迫代替她去往敵國(guó)和親眼耀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 概述 本篇較長(zhǎng)佩憾,九神帶你從0入門(mén)JVM哮伟,全文包括包括JVM的分類、JVM垃圾回收綜述妄帘、JVM的內(nèi)存模型(Java ...
    九神說(shuō)編程閱讀 445評(píng)論 0 1
  • 前言 在這篇文章介紹并記錄關(guān)于JVM內(nèi)存結(jié)構(gòu)的簡(jiǎn)單應(yīng)用學(xué)習(xí)楞黄。基于JDK8抡驼。 1.JVM內(nèi)存結(jié)構(gòu) 1.1運(yùn)行時(shí)數(shù)據(jù)區(qū)...
    西茶閱讀 423評(píng)論 0 0
  • 前言 只有光頭才能變強(qiáng) JVM在準(zhǔn)備面試的時(shí)候就有看了致盟,一直沒(méi)時(shí)間寫(xiě)筆記∷樗埃現(xiàn)在到了一家公司實(shí)習(xí)柏副,閑的時(shí)候就寫(xiě)寫(xiě),刷...
    Java3y閱讀 25,549評(píng)論 11 129
  • 久違的晴天蚣录,家長(zhǎng)會(huì)割择。 家長(zhǎng)大會(huì)開(kāi)好到教室時(shí),離放學(xué)已經(jīng)沒(méi)多少時(shí)間了萎河。班主任說(shuō)已經(jīng)安排了三個(gè)家長(zhǎng)分享經(jīng)驗(yàn)荔泳。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,524評(píng)論 16 22
  • 今天感恩節(jié)哎,感謝一直在我身邊的親朋好友虐杯。感恩相遇玛歌!感恩不離不棄。 中午開(kāi)了第一次的黨會(huì)擎椰,身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,569評(píng)論 0 11