三色標(biāo)記法是一種垃圾回收法钢坦,它可以讓JVM不發(fā)生或僅短時間發(fā)生STW(Stop The World),從而達(dá)到清除JVM內(nèi)存垃圾的目的啥酱。
JVM中的CMS爹凹、G1垃圾回收器所使用垃圾回收算法即為三色標(biāo)記法。
三色標(biāo)記法-算法思想
三色標(biāo)記法將對象的顏色分為了黑镶殷、灰禾酱、白,三種顏色绘趋。
黑色:該對象已經(jīng)被標(biāo)記過了颤陶,且該對象下的屬性也全部都被標(biāo)記過了。(程序所需要的對象)
灰色:該對象已經(jīng)被標(biāo)記過了陷遮,但該對象下的屬性沒有全被標(biāo)記完滓走。(GC需要從此對象中去尋找垃圾)
白色:該對象沒有被標(biāo)記過。(對象垃圾)
算法流程:
從我們main方法的根對象(JVM中稱為GC Root)開始沿著他們的對象向下查找帽馋,用黑灰白的規(guī)則搅方,標(biāo)記出所有跟GC Root相連接的對象
掃描一遍結(jié)束后,一般需要進(jìn)行一次短暫的STW(Stop The World)绽族,再次進(jìn)行掃描姨涡,此時因為黑色對象的屬性都也已經(jīng)被標(biāo)記過了,所以只需找出灰色對象并順著繼續(xù)往下標(biāo)記(且因為大部分的標(biāo)記工作已經(jīng)在第一次并發(fā)的時候發(fā)生了,所以灰色對象數(shù)量會很少,標(biāo)記時間也會短很多)
此時程序繼續(xù)執(zhí)行逾冬,GC線程掃描所有的內(nèi)存,找出被標(biāo)記為白色的對象(垃圾)清除
存在問題:
浮動垃圾:并發(fā)標(biāo)記的過程中瘸羡,若一個已經(jīng)被標(biāo)記成黑色或者灰色的對象,突然變成了垃圾,此時,此對象不是白色的不會被清除悠轩,重新標(biāo)記也不能從GC Root中去找到,所以成為了浮動垃圾涕癣,這種情況對系統(tǒng)的影響不大哗蜈,留給下一次GC進(jìn)行處理即可。
對象漏標(biāo)問題(需要的對象被回收):并發(fā)標(biāo)記的過程中坠韩,一個業(yè)務(wù)線程將一個未被掃描過的白色對象斷開引用成為垃圾(刪除引用)距潘,同時黑色對象引用了該對象(增加引用)(這兩部可以不分先后順序);因為黑色對象的含義為其屬性都已經(jīng)被標(biāo)記過了只搁,重新標(biāo)記也不會從黑色對象中去找音比,導(dǎo)致該對象被程序所需要,卻又要被GC回收氢惋,此問題會導(dǎo)致系統(tǒng)出現(xiàn)問題洞翩,而CMS與G1,兩種回收器在使用三色標(biāo)記法時焰望,都采取了一些措施來應(yīng)對這些問題骚亿,CMS對增加引用環(huán)節(jié)進(jìn)行處理(Increment Update),G1則對刪除引用環(huán)節(jié)進(jìn)行處理(SATB)熊赖。
三色標(biāo)記法的實踐與應(yīng)對對象漏標(biāo)問題的具體做法
在JVM虛擬機中有兩種常見垃圾回收器使用了該算法:
CMS(Concurrent Mark Sweep)
G1(Garbage First)
CMS(Concurrent Mark Sweep)
CMS来屠,是非常有名的JVM垃圾回收器,它起到了承上啟下的作用震鹉,開啟了并發(fā)回收的篇章俱笛。
但是CMS由于許多小問題,現(xiàn)在基本已經(jīng)被淘汰传趾。
增量更新(Increment Update)
在應(yīng)對漏標(biāo)問題時迎膜,CMS使用了Increment Update方法來做:
在一個未被標(biāo)記的對象(白色對象)被重新引用后,==引用它的對象==浆兰,若為黑色則要變成灰色磕仅,在下次二次標(biāo)記時讓GC線程繼續(xù)標(biāo)記它的屬性對象。
但是就算時這樣镊讼,其仍然是存在漏標(biāo)的問題:
在一個灰色對象正在被一個GC線程回收時宽涌,當(dāng)它已經(jīng)被標(biāo)記過的屬性指向了一個白色對象(垃圾)
而這個對象的屬性對象本身還未全部標(biāo)記結(jié)束,則為灰色不變
而這個GC線程在標(biāo)記完最后一個屬性后蝶棋,認(rèn)為已經(jīng)將所有的屬性標(biāo)記結(jié)束了卸亮,將這個灰色對象標(biāo)記為黑色,被重新引用的白色對象玩裙,無法被標(biāo)記
補充兼贸,CMS除了這個缺陷外,仍然存在兩個個較為致命的缺陷:
CMS采用了Mark-Sweep算法吃溅,最后會產(chǎn)生許多內(nèi)存碎片溶诞,當(dāng)?shù)揭欢〝?shù)量時,CMS無法清理這些碎片了决侈,CMS會讓Serial Old來清理這些垃圾碎片螺垢,而Serial Old是單線程操作進(jìn)行清理垃圾的,效率偏低。
所以使用CMS就會出現(xiàn)一種情況枉圃,硬件升級了功茴,卻越來越卡頓,其原因就是因為進(jìn)行Serial Old GC時孽亲,效率過低坎穿。
解決方案:使用Mark-Sweep-Compact算法,減少垃圾碎片
調(diào)優(yōu)參數(shù)(配套使用):
-XX:+UseCMSCompactAtFullCollection 開啟CMS的壓縮
-XX:CMSFullGCsBeforeCompaction 默認(rèn)為0返劲,指經(jīng)過多少次CMS FullGC才進(jìn)行壓縮
當(dāng)JVM認(rèn)為內(nèi)存不夠了玲昧,再使用CMS進(jìn)行并發(fā)清理內(nèi)存可能會發(fā)生OOM的問題,而不得不進(jìn)行Serial Old GC篮绿,Serial Old是單線程垃圾回收孵延,效率低
解決方案:降低觸發(fā)CMS GC的閾值,讓浮動垃圾不那么容易占滿老年代
調(diào)優(yōu)參數(shù):
-XX:CMSInitiatingOccupancyFraction 92% 可以降低這個值亲配,讓老年代占用率達(dá)到該值就進(jìn)行CMS GC
G1(Garbage First)
從G1垃圾回收器開始隙袁,G1的物理內(nèi)存不再分代,而是由一塊一塊的Region組成弃榨;邏輯分代仍然存在菩收。
前置知識 — Card Table(多種垃圾回收器均具備)
由于在進(jìn)行YoungGC時,我們在進(jìn)行對一個對象是否被引用的過程鲸睛,需要掃描整個Old區(qū)娜饵,所以JVM設(shè)計了CardTable,將Old區(qū)分為一個一個Card官辈,一個Card有多個對象箱舞;如果一個Card中的對象有引用指向Young區(qū),則將其標(biāo)記為Dirty Card拳亿,下次需要進(jìn)行YoungGC時晴股,只需要去掃描Dirty Card即可。
Card Table 在底層數(shù)據(jù)結(jié)構(gòu)以 Bit Map實現(xiàn)肺魁。
CSet(Collection Set)
一組可被回收的分區(qū)Region的集合电湘;Region,是多個對象的集合內(nèi)存區(qū)域鹅经。
RSet(Remembered Set)
每個Region中都有一個RSet寂呛,記錄其他Region到本Region的引用信息;使得垃圾回收器不需要掃描整個堆找到誰引用當(dāng)前分區(qū)中的對象瘾晃,只需要掃描RSet即可贷痪。
新生代與老年代的比例
5% - 60%,一般不使用手工指定蹦误,因為這是G1預(yù)測停頓時間的基準(zhǔn)劫拢。
SATB(Snapshot At The Beginning)
在應(yīng)對漏標(biāo)問題時肉津,CMS使用了SATB方法來做:
在開始標(biāo)記的時候生成一個快照圖標(biāo)記存活對象
在一個引用斷開后,要將此引用推到GC的堆棧里舱沧,保證白色對象(垃圾)還能被GC線程掃描到
配合Rset阀圾,去掃描哪些Region引用到當(dāng)前的白色對象,若沒有引用到當(dāng)前對象狗唉,則回收
SATB效率高于Increment update原因?
因為SATB在重新標(biāo)記環(huán)節(jié)只需要去重新掃描那些被推到堆棧中的引用涡真,并配合Rset來判斷當(dāng)前對象是否被引用來進(jìn)行回收分俯;
并且在最后G1并不會選擇回收所有垃圾對象,而是根據(jù)Region的垃圾多少來判斷與預(yù)估回收價值(指回收的垃圾與回收的STW時間的一個預(yù)估值)哆料,將一個或者多個Region放到CSet中缸剪,最后將這些Region中的存活對象壓縮并復(fù)制到新的Region中,清空原來的Region东亦。
問題:G1會不會進(jìn)行Full GC?
會杏节,當(dāng)內(nèi)存滿了的時候就會進(jìn)行Full GC;且JDK10之前的Full GC典阵,為單線程的奋渔,所以使用G1需要避免Full GC的產(chǎn)生。
解決方案:
加大內(nèi)存壮啊;
提高CPU性能嫉鲸,加快GC回收速度,而對象增加速度趕不上回收速度歹啼,則Full GC可以避免玄渗;
降低進(jìn)行Mixed GC觸發(fā)的閾值,讓Mixed GC提早發(fā)生(默認(rèn)45%)
G1介紹
G1的第一篇paper(附錄1)發(fā)表于2004年狸眼,在2012年才在jdk1.7u4中可用藤树。oracle官方計劃在jdk9中將G1變成默認(rèn)的垃圾收集器,以替代CMS拓萌。為何oracle要極力推薦G1呢岁钓,G1有哪些優(yōu)點?
首先微王,G1的設(shè)計原則就是簡單可行的性能調(diào)優(yōu)
開發(fā)人員僅僅需要聲明以下參數(shù)即可:
-XX:+UseG1GC -Xmx32g -XX:MaxGCPauseMillis=200
其中-XX:+UseG1GC為開啟G1垃圾收集器甜紫,-Xmx32g 設(shè)計堆內(nèi)存的最大內(nèi)存為32G,-XX:MaxGCPauseMillis=200設(shè)置GC的最大暫停時間為200ms骂远。如果我們需要調(diào)優(yōu)囚霸,在內(nèi)存大小一定的情況下,我們只需要修改最大暫停時間即可激才。
其次拓型,G1將新生代额嘿,老年代的物理空間劃分取消了。
這樣我們再也不用單獨的空間對每個代進(jìn)行設(shè)置了劣挫,不用擔(dān)心每個代內(nèi)存是否足夠册养。
取而代之的是,G1算法將堆劃分為若干個區(qū)域(Region)压固,它仍然屬于分代收集器球拦。不過,這些區(qū)域的一部分包含新生代帐我,新生代的垃圾收集依然采用暫停所有應(yīng)用線程的方式坎炼,將存活對象拷貝到老年代或者Survivor空間。老年代也分成很多區(qū)域拦键,G1收集器通過將對象從一個區(qū)域復(fù)制到另外一個區(qū)域谣光,完成了清理工作。這就意味著芬为,在正常的處理過程中萄金,G1完成了堆的壓縮(至少是部分堆的壓縮),這樣也就不會有cms內(nèi)存碎片問題的存在了媚朦。
在G1中氧敢,還有一種特殊的區(qū)域,叫Humongous區(qū)域询张。 如果一個對象占用的空間超過了分區(qū)容量50%以上福稳,G1收集器就認(rèn)為這是一個巨型對象。這些巨型對象瑞侮,默認(rèn)直接會被分配在年老代的圆,但是如果它是一個短期存在的巨型對象,就會對垃圾收集器造成負(fù)面影響半火。為了解決這個問題越妈,G1劃分了一個Humongous區(qū),它用來專門存放巨型對象钮糖。如果一個H區(qū)裝不下一個巨型對象梅掠,那么G1會尋找連續(xù)的H分區(qū)來存儲。為了能找到連續(xù)的H區(qū)店归,有時候不得不啟動Full GC阎抒。
PS:在java 8中,持久代也移動到了普通的堆內(nèi)存空間中消痛,改為元空間且叁。
對象分配策略
說起大對象的分配,我們不得不談?wù)剬ο蟮姆峙洳呗灾壬 K譃?個階段:
TLAB(Thread Local Allocation Buffer)線程本地分配緩沖區(qū)
Eden區(qū)中分配
Humongous區(qū)分配
TLAB為線程本地分配緩沖區(qū)逞带,它的目的為了使對象盡可能快的分配出來欺矫。如果對象在一個共享的空間中分配,我們需要采用一些同步機制來管理這些空間內(nèi)的空閑空間指針展氓。在Eden空間中穆趴,每一個線程都有一個固定的分區(qū)用于分配對象,即一個TLAB遇汞。分配對象時未妹,線程之間不再需要進(jìn)行任何的同步。
對TLAB空間中無法分配的對象空入,JVM會嘗試在Eden空間中進(jìn)行分配络它。如果Eden空間無法容納該對象,就只能在老年代中進(jìn)行分配空間执庐。
最后,G1提供了兩種GC模式导梆,Young GC和Mixed GC轨淌,兩種都是Stop The World(STW)的。下面我們將分別介紹一下這2種模式看尼。
G1 Young GC
Young GC主要是對Eden區(qū)進(jìn)行GC递鹉,它在Eden空間耗盡時會被觸發(fā)。在這種情況下藏斩,Eden空間的數(shù)據(jù)移動到Survivor空間中躏结,如果Survivor空間不夠,Eden空間的部分?jǐn)?shù)據(jù)會直接晉升到年老代空間狰域。Survivor區(qū)的數(shù)據(jù)移動到新的Survivor區(qū)中媳拴,也有部分?jǐn)?shù)據(jù)晉升到老年代空間中。最終Eden空間的數(shù)據(jù)為空兆览,GC停止工作屈溉,應(yīng)用線程繼續(xù)執(zhí)行。
這時抬探,我們需要考慮一個問題子巾,如果僅僅GC 新生代對象,我們?nèi)绾握业剿械母鶎ο竽兀?老年代的所有對象都是根么小压?那這樣掃描下來會耗費大量的時間线梗。于是,G1引進(jìn)了RSet的概念怠益。它的全稱是Remembered Set仪搔,作用是跟蹤指向某個heap區(qū)內(nèi)的對象引用。
在CMS中蜻牢,也有RSet的概念僻造,在老年代中有一塊區(qū)域用來記錄指向新生代的引用憋他。這是一種point-out,在進(jìn)行Young GC時髓削,掃描根時竹挡,僅僅需要掃描這一塊區(qū)域,而不需要掃描整個老年代立膛。
但在G1中揪罕,并沒有使用point-out,這是由于一個分區(qū)太小宝泵,分區(qū)數(shù)量太多好啰,如果是用point-out的話,會造成大量的掃描浪費儿奶,有些根本不需要GC的分區(qū)引用也掃描了框往。于是G1中使用point-in來解決。point-in的意思是哪些分區(qū)引用了當(dāng)前分區(qū)中的對象闯捎。這樣椰弊,僅僅將這些對象當(dāng)做根來掃描就避免了無效的掃描。由于新生代有多個瓤鼻,那么我們需要在新生代之間記錄引用嗎秉版?這是不必要的,原因在于每次GC時茬祷,所有新生代都會被掃描清焕,所以只需要記錄老年代到新生代之間的引用即可。
需要注意的是祭犯,如果引用的對象很多秸妥,賦值器需要對每個引用做處理,賦值器開銷會很大沃粗,為了解決賦值器開銷這個問題筛峭,在G1 中又引入了另外一個概念,卡表(Card Table)陪每。一個Card Table將一個分區(qū)在邏輯上劃分為固定大小的連續(xù)區(qū)域影晓,每個區(qū)域稱之為卡¢莺蹋卡通常較小挂签,介于128到512字節(jié)之間。Card Table通常為字節(jié)數(shù)組盼产,由Card的索引(即數(shù)組下標(biāo))來標(biāo)識每個分區(qū)的空間地址饵婆。默認(rèn)情況下,每個卡都未被引用戏售。當(dāng)一個地址空間被引用時侨核,這個地址空間對應(yīng)的數(shù)組索引的值被標(biāo)記為”0″草穆,即標(biāo)記為臟被引用,此外RSet也將這個數(shù)組下標(biāo)記錄下來搓译。一般情況下悲柱,這個RSet其實是一個Hash Table,Key是別的Region的起始地址些己,Value是一個集合豌鸡,里面的元素是Card Table的Index。
Young GC 階段:
階段1:根掃描
靜態(tài)和本地對象被掃描
階段2:更新RS
處理dirty card隊列更新RS
階段3:處理RS
檢測從年輕代指向年老代的對象
階段4:對象拷貝
拷貝存活的對象到survivor/old區(qū)域
階段5:處理引用隊列
軟引用段标,弱引用涯冠,虛引用處理
G1 Mix GC
Mix GC不僅進(jìn)行正常的新生代垃圾收集,同時也回收部分后臺掃描線程標(biāo)記的老年代分區(qū)逼庞。
它的GC步驟分2步:
全局并發(fā)標(biāo)記(global concurrent marking)
拷貝存活對象(evacuation)
在進(jìn)行Mix GC之前蛇更,會先進(jìn)行g(shù)lobal concurrent marking(全局并發(fā)標(biāo)記)。 global concurrent marking的執(zhí)行過程是怎樣的呢赛糟?
在G1 GC中派任,它主要是為Mixed GC提供標(biāo)記服務(wù)的,并不是一次GC過程的一個必須環(huán)節(jié)虑灰。global concurrent marking的執(zhí)行過程分為五個步驟:
初始標(biāo)記(initial mark吨瞎,STW)
在此階段痹兜,G1 GC 對根進(jìn)行標(biāo)記穆咐。該階段與常規(guī)的 (STW) 年輕代垃圾回收密切相關(guān)。
根區(qū)域掃描(root region scan)
G1 GC 在初始標(biāo)記的存活區(qū)掃描對老年代的引用字旭,并標(biāo)記被引用的對象对湃。該階段與應(yīng)用程序(非 STW)同時運行,并且只有完成該階段后遗淳,才能開始下一次 STW 年輕代垃圾回收拍柒。
并發(fā)標(biāo)記(Concurrent Marking)
G1 GC 在整個堆中查找可訪問的(存活的)對象。該階段與應(yīng)用程序同時運行屈暗,可以被 STW 年輕代垃圾回收中斷
最終標(biāo)記(Remark拆讯,STW)
該階段是 STW 回收,幫助完成標(biāo)記周期养叛。G1 GC 清空 SATB 緩沖區(qū)种呐,跟蹤未被訪問的存活對象,并執(zhí)行引用處理弃甥。
清除垃圾(Cleanup爽室,STW)
在這個最后階段,G1 GC 執(zhí)行統(tǒng)計和 RSet 凈化的 STW 操作淆攻。在統(tǒng)計期間阔墩,G1 GC 會識別完全空閑的區(qū)域和可供進(jìn)行混合垃圾回收的區(qū)域嘿架。清理階段在將空白區(qū)域重置并返回到空閑列表時為部分并發(fā)。
三色標(biāo)記算法
提到并發(fā)標(biāo)記啸箫,我們不得不了解并發(fā)標(biāo)記的三色標(biāo)記算法耸彪。它是描述追蹤式回收器的一種有用的方法,利用它可以推演回收器的正確性筐高。 首先搜囱,我們將對象分成三種類型的。
黑色:根對象柑土,或者該對象與它的子對象都被掃描
灰色:對象本身被掃描,但還沒掃描完該對象中的子對象
白色:未被掃描對象蜀肘,掃描完成所有對象之后,最終為白色的為不可達(dá)對象稽屏,即垃圾對象
當(dāng)GC開始掃描對象時扮宠,按照如下圖步驟進(jìn)行對象的掃描:
根對象被置為黑色,子對象被置為灰色狐榔。
繼續(xù)由灰色遍歷,將已掃描了子對象的對象置為黑色坛增。
遍歷了所有可達(dá)的對象后,所有可達(dá)的對象都變成了黑色薄腻。不可達(dá)的對象即為白色收捣,需要被清理。
這看起來很美好庵楷,但是如果在標(biāo)記過程中罢艾,應(yīng)用程序也在運行,那么對象的指針就有可能改變尽纽。這樣的話咐蚯,我們就會遇到一個問題:對象丟失問題
我們看下面一種情況,當(dāng)垃圾收集器掃描到下面情況時:
這時候應(yīng)用程序執(zhí)行了以下操作:
A.c=C
B.c=null
這樣弄贿,對象的狀態(tài)圖變成如下情形:
這時候垃圾收集器再標(biāo)記掃描的時候就會下圖成這樣:
很顯然春锋,此時C是白色,被認(rèn)為是垃圾需要清理掉差凹,顯然這是不合理的期奔。那么我們?nèi)绾伪WC應(yīng)用程序在運行的時候,GC標(biāo)記的對象不丟失呢危尿?有如下2中可行的方式:
在插入的時候記錄對象
在刪除的時候記錄對象
剛好這對應(yīng)CMS和G1的2種不同實現(xiàn)方式:
在CMS采用的是增量更新(Incremental update)呐萌,只要在寫屏障(write barrier)里發(fā)現(xiàn)要有一個白對象的引用被賦值到一個黑對象 的字段里,那就把這個白對象變成灰色的脚线。即插入的時候記錄下來搁胆。
在G1中,使用的是STAB(snapshot-at-the-beginning)的方式,刪除的時候記錄所有的對象渠旁,它有3個步驟:
1攀例,在開始標(biāo)記的時候生成一個快照圖標(biāo)記存活對象
2,在并發(fā)標(biāo)記的時候所有被改變的對象入隊(在write barrier里把所有舊的引用所指向的對象都變成非白的)
3顾腊,可能存在游離的垃圾粤铭,將在下次被收集
這樣,G1到現(xiàn)在可以知道哪些老的分區(qū)可回收垃圾最多杂靶。 當(dāng)全局并發(fā)標(biāo)記完成后梆惯,在某個時刻,就開始了Mix GC吗垮。這些垃圾回收被稱作“混合式”是因為他們不僅僅進(jìn)行正常的新生代垃圾收集垛吗,同時也回收部分后臺掃描線程標(biāo)記的分區(qū)∷傅牵混合式垃圾收集如下圖:
混合式GC也是采用的復(fù)制的清理策略怯屉,當(dāng)GC完成后,會重新釋放空間饵沧。
至此锨络,混合式GC告一段落了。下一小節(jié)我們講進(jìn)入調(diào)優(yōu)實踐狼牺。
調(diào)優(yōu)實踐
MaxGCPauseMillis調(diào)優(yōu)
前面介紹過使用GC的最基本的參數(shù):
-XX:+UseG1GC -Xmx32g -XX:MaxGCPauseMillis=200 -XX:+PrintGCDetails
前面2個參數(shù)都好理解羡儿,后面這個MaxGCPauseMillis參數(shù)該怎么配置呢?這個參數(shù)從字面的意思上看是钥,就是允許的GC最大的暫停時間掠归。G1盡量確保每次GC暫停的時間都在設(shè)置的MaxGCPauseMillis范圍內(nèi)。 那G1是如何做到最大暫停時間的呢咏瑟?這涉及到另一個概念拂到,CSet(collection set)痪署。它的意思是在一次垃圾收集器中被收集的區(qū)域集合码泞。
Young GC:選定所有新生代里的region。通過控制新生代的region個數(shù)來控制young GC的開銷狼犯。
Mixed GC:選定所有新生代里的region余寥,外加根據(jù)global concurrent marking統(tǒng)計得出收集收益高的若干老年代region。在用戶指定的開銷目標(biāo)范圍內(nèi)盡可能選擇收益高的老年代region悯森。
在理解了這些后宋舷,我們再設(shè)置最大暫停時間就好辦了。 首先瓢姻,我們能容忍的最大暫停時間是有一個限度的祝蝠,我們需要在這個限度范圍內(nèi)設(shè)置。但是應(yīng)該設(shè)置的值是多少呢?我們需要在吞吐量跟MaxGCPauseMillis之間做一個平衡绎狭。如果MaxGCPauseMillis設(shè)置的過小细溅,那么GC就會頻繁,吞吐量就會下降儡嘶。如果MaxGCPauseMillis設(shè)置的過大喇聊,應(yīng)用程序暫停時間就會變長。G1的默認(rèn)暫停時間是200毫秒蹦狂,我們可以從這里入手誓篱,調(diào)整合適的時間。
其他調(diào)優(yōu)參數(shù)
-XX:G1HeapRegionSize=n
設(shè)置的 G1 區(qū)域的大小凯楔。值是 2 的冪窜骄,范圍是 1 MB 到 32 MB 之間。目標(biāo)是根據(jù)最小的 Java 堆大小劃分出約 2048 個區(qū)域摆屯。
-XX:ParallelGCThreads=n
設(shè)置 STW 工作線程數(shù)的值啊研。將 n 的值設(shè)置為邏輯處理器的數(shù)量。n 的值與邏輯處理器的數(shù)量相同鸥拧,最多為 8党远。
如果邏輯處理器不止八個,則將 n 的值設(shè)置為邏輯處理器數(shù)的 5/8 左右富弦。這適用于大多數(shù)情況沟娱,除非是較大的 SPARC 系統(tǒng),其中 n 的值可以是邏輯處理器數(shù)的 5/16 左右腕柜。
-XX:ConcGCThreads=n
設(shè)置并行標(biāo)記的線程數(shù)济似。將 n 設(shè)置為并行垃圾回收線程數(shù) (ParallelGCThreads) 的 1/4 左右。
-XX:InitiatingHeapOccupancyPercent=45
設(shè)置觸發(fā)標(biāo)記周期的 Java 堆占用率閾值盏缤。默認(rèn)占用率是整個 Java 堆的 45%砰蠢。
避免使用以下參數(shù):
避免使用 -Xmn 選項或 -XX:NewRatio 等其他相關(guān)選項顯式設(shè)置年輕代大小。固定年輕代的大小會覆蓋暫停時間目標(biāo)唉铜。
觸發(fā)Full GC
在某些情況下台舱,G1觸發(fā)了Full GC,這時G1會退化使用Serial收集器來完成垃圾的清理工作潭流,它僅僅使用單線程來完成GC工作竞惋,GC暫停時間將達(dá)到秒級別的。整個應(yīng)用處于假死狀態(tài)灰嫉,不能處理任何請求拆宛,我們的程序當(dāng)然不希望看到這些。那么發(fā)生Full GC的情況有哪些呢讼撒?
并發(fā)模式失敗
G1啟動標(biāo)記周期浑厚,但在Mix GC之前股耽,老年代就被填滿,這時候G1會放棄標(biāo)記周期钳幅。這種情形下豺谈,需要增加堆大小,或者調(diào)整周期(例如增加線程數(shù)-XX:ConcGCThreads等)贡这。
晉升失敗或者疏散失敗
G1在進(jìn)行GC的時候沒有足夠的內(nèi)存供存活對象或晉升對象使用茬末,由此觸發(fā)了Full GC「墙茫可以在日志中看到(to-space exhausted)或者(to-space overflow)丽惭。解決這種問題的方式是:
a,增加 -XX:G1ReservePercent 選項的值(并相應(yīng)增加總的堆大小)辈双,為“目標(biāo)空間”增加預(yù)留內(nèi)存量责掏。
b,通過減少 -XX:InitiatingHeapOccupancyPercent 提前啟動標(biāo)記周期。
c,也可以通過增加 -XX:ConcGCThreads 選項的值來增加并行標(biāo)記線程的數(shù)目湃望。
巨型對象分配失敗
當(dāng)巨型對象找不到合適的空間進(jìn)行分配時换衬,就會啟動Full GC,來釋放空間证芭。這種情況下瞳浦,應(yīng)該避免分配大量的巨型對象,增加內(nèi)存或者增大-XX:G1HeapRegionSize废士,使巨型對象不再是巨型對象叫潦。
由于篇幅有限,G1還有很多調(diào)優(yōu)實踐官硝,在此就不一一列出了矗蕊,大家在平常的實踐中可以慢慢探索。最后氢架,期待java 9能正式發(fā)布傻咖,默認(rèn)使用G1為垃圾收集器的java性能會不會又提高呢?
G1相關(guān)處理參數(shù)*
G1處理和傳統(tǒng)的垃圾收集策略是不同的岖研,關(guān)鍵的因素是它將所有的內(nèi)存進(jìn)行了子區(qū)域的劃分卿操。
總結(jié)
普遍存在:全內(nèi)存掃描問題。
傳統(tǒng)的收集器不能滿足高內(nèi)存高cpu的要求缎玫,這才是G1產(chǎn)生的原因硬纤。
G1是一款非常優(yōu)秀的垃圾收集器解滓,不僅適合堆內(nèi)存大的應(yīng)用赃磨,同時也簡化了調(diào)優(yōu)的工作。通過主要的參數(shù)初始和最大堆空間洼裤、以及最大容忍的GC暫停目標(biāo)邻辉,就能得到不錯的性能;同時,我們也看到G1對內(nèi)存空間的浪費較高值骇,但通過**首先收集盡可能多的垃圾(Garbage First)的設(shè)計原則莹菱,可以及時發(fā)現(xiàn)過期對象,從而讓內(nèi)存占用處于合理的水平吱瘩。
參考鏈接:
https://juejin.cn/post/6859931488352370702
https://blog.csdn.net/qq_39276448/article/details/104470796