本篇內(nèi)容主要講解“G1垃圾回收器與CMS的區(qū)別有哪些”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“G1垃圾回收器與CMS的區(qū)別有哪些”吧!
創(chuàng)新互聯(lián)主營(yíng)名山網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,重慶APP開(kāi)發(fā),名山h5小程序制作搭建,名山網(wǎng)站營(yíng)銷推廣歡迎名山等地區(qū)企業(yè)咨詢
在G1之前的垃圾收集器,將堆區(qū)主要?jiǎng)澐至薊den區(qū),Old區(qū),Survivor區(qū)。其中對(duì)于Eden,Survivor對(duì)回收過(guò)程來(lái)說(shuō)叫做“年輕代垃圾收集”。并且年輕代和老年代都分別是連續(xù)的內(nèi)存空間。G1將堆分成了若干Region,Region的大小可以通過(guò)G1HeapRegionSize參數(shù)進(jìn)行設(shè)置,其必須是2的冪,范圍允許為1Mb到32Mb。 JVM的會(huì)基于堆內(nèi)存的初始值和最大值的平均數(shù)計(jì)算分區(qū)的尺寸,平均的堆尺寸會(huì)分出約2000個(gè)Region。分區(qū)大小一旦設(shè)置,則啟動(dòng)之后不會(huì)再變化。
Eden regions(年輕代-Eden區(qū))
Survivor regions(年輕代-Survivor區(qū))
Old regions(老年代)
Humongous regions(巨型對(duì)象區(qū)域)
Free resgions(未分配區(qū)域,也會(huì)叫做可用分區(qū))
1)G1還是采用分代回收,但是不同的分代之間內(nèi)存不一定是連續(xù)的,不同分代的Region的占用數(shù)也不一定是固定的(不建議通過(guò)相關(guān)選項(xiàng)顯式設(shè)置年輕代大小。會(huì)覆蓋暫停時(shí)間目標(biāo))。年輕代的Eden,Survivor數(shù)量會(huì)隨著每一次GC發(fā)生相應(yīng)的改變。
2)分區(qū)是不固定屬于哪個(gè)分代的,所以比如一次ygc過(guò)后,原來(lái)的Eden的分區(qū)就會(huì)變成空閑的可用分區(qū),隨后也可能被用作分配巨型對(duì)象,成為H區(qū)等。
3)G1中的巨型對(duì)象是指,占用了Region容量的50%以上的一個(gè)對(duì)象。Humongous區(qū),就專門用來(lái)存儲(chǔ)巨型對(duì)象。如果一個(gè)H區(qū)裝不下一個(gè)巨型對(duì)象,則會(huì)通過(guò)連續(xù)的若干H分區(qū)來(lái)存儲(chǔ)。因?yàn)榫扌蛯?duì)象的轉(zhuǎn)移會(huì)影響GC效率,所以并發(fā)標(biāo)記階段發(fā)現(xiàn)巨型對(duì)象不再存活時(shí),會(huì)將其直接回收。ygc也會(huì)在某些情況下對(duì)巨型對(duì)象進(jìn)行回收。
4)分區(qū)可以有效利用內(nèi)存空間,因?yàn)槭占w是使用“標(biāo)記-整理”,Region之間基于“復(fù)制”算法,GC后會(huì)將存活對(duì)象復(fù)制到可用分區(qū)(未分配的分區(qū)),所以不會(huì)產(chǎn)生空間碎片。
5)G1類似CMS,也會(huì)在比如一次fullgc中基于堆尺寸的計(jì)算重新調(diào)整(增加)堆的空間。但是相較于執(zhí)行fullgc,G1 GC會(huì)在無(wú)法分配對(duì)象或者巨型對(duì)象無(wú)法獲得連續(xù)分區(qū)來(lái)分配空間時(shí),優(yōu)先嘗試擴(kuò)展堆空間來(lái)獲得更多的可用分區(qū)。原則上就是G1會(huì)計(jì)算執(zhí)行GC的時(shí)間,并且極力減少花在GC上的時(shí)間(包括ygc,mixgc),如果可能,會(huì)通過(guò)不斷擴(kuò)展堆空間來(lái)滿足對(duì)象分配、轉(zhuǎn)移的需要。
6)因?yàn)镚1提供了“可預(yù)測(cè)的暫停時(shí)間”,也是基于G1的啟發(fā)式算法,所以G1會(huì)估算年輕代需要多少分區(qū),以及還有多少分區(qū)要被回收。younggc觸發(fā)的契機(jī)就是在Eden分區(qū)數(shù)量達(dá)到上限時(shí)。一次younggc會(huì)回收所有的Eden和survivor區(qū)。其中存活的對(duì)象會(huì)被轉(zhuǎn)移到另一個(gè)新的survivor區(qū)或者old區(qū),如果轉(zhuǎn)移的目標(biāo)分區(qū)滿了,會(huì)再將可用區(qū)標(biāo)記成S或者O區(qū)。
TLAB(Thread Local Allocation Buffer)本地線程緩沖區(qū)
G1 GC會(huì)默認(rèn)會(huì)啟用Tlab優(yōu)化。其作用就是在并發(fā)情況下,基于CAS的獨(dú)享線程(mutator threads)可以優(yōu)先將對(duì)象分配在一塊內(nèi)存區(qū)域(屬于Java堆的Eden中),只是因?yàn)槭荍ava線程獨(dú)享的內(nèi)存區(qū),沒(méi)有鎖競(jìng)爭(zhēng),所以分配速度更快,每個(gè)Tlab都是一個(gè)線程獨(dú)享的。如果待分配的對(duì)象被判斷是巨型對(duì)象,則不使用TLAB。
PLAB(Promotion Local Allocation Buffer) 晉升本地分配緩沖區(qū)
在younggc中,對(duì)象會(huì)將全部Eden區(qū)存活的對(duì)象轉(zhuǎn)移(復(fù)制)到S區(qū)分區(qū)。也會(huì)存在S區(qū)對(duì)象晉升(Promotion)到老年代。這個(gè)決定晉升的閥值可以通過(guò)MaxTenuringThreshold設(shè)定。晉升的過(guò)程,無(wú)論是晉升到S還是O區(qū),都是在GC線程的PLAB中進(jìn)行。每個(gè)GC線程都有一個(gè)PLAB。
Collection Sets(CSets)待收集集合
GC中待回收的region的集合。CSet中可能存放著各個(gè)分代的Region。CSet中的存活對(duì)象會(huì)在gc中被移動(dòng)(復(fù)制)。GC后CSet中的region會(huì)成為可用分區(qū)。
Remembered Sets(RSets)已記憶集合
已記憶集合在每個(gè)分區(qū)中都存在,并且每個(gè)分區(qū)只有一個(gè)RSet。其中存儲(chǔ)著其他分區(qū)中的對(duì)象對(duì)本分區(qū)對(duì)象的引用,是一種points-in結(jié)構(gòu)。ygc的時(shí)候,只要掃描RSet中的old區(qū)對(duì)象對(duì)于本young區(qū)的引用,不需要掃描所有old區(qū)。mixed gc時(shí),掃描Old區(qū)的RSet中,其他old區(qū)對(duì)于本old分區(qū)的引用,一樣不用掃描所有的old區(qū)。提高了GC效率。因?yàn)槊看蜧C都會(huì)掃描所有young區(qū)對(duì)象,所以RSet只有在掃描old引用young,old引用old時(shí)會(huì)被使用。
Card Table 卡表
將Java堆劃分為相等大小的一個(gè)個(gè)區(qū)域,這個(gè)小的區(qū)域(一般size在128-512字節(jié))被當(dāng)做Card,而Card Table維護(hù)著所有的Card。Card Table的結(jié)構(gòu)是一個(gè)字節(jié)數(shù)組,Card Table用單字節(jié)的信息映射著一個(gè)Card。當(dāng)Card中存儲(chǔ)了對(duì)象時(shí),稱為這個(gè)Card被臟化了(dirty card)。 對(duì)于一些熱點(diǎn)Card會(huì)存放到Hot card cache。同Card Table一樣,Hot card cache也是全局的結(jié)構(gòu)。
CMS收集器僅作用于老年代的收集,是基于標(biāo)記-清除算法的,它的運(yùn)作過(guò)程分為4個(gè)步驟:
初始標(biāo)記(CMS initial mark)獨(dú)占CPU(STW),僅標(biāo)記GCroots能直接關(guān)聯(lián)的對(duì)象
并發(fā)標(biāo)記(CMS concurrent mark)可以和用戶線程并行執(zhí)行,標(biāo)記所有可達(dá)對(duì)象
重新標(biāo)記(CMS remark)獨(dú)占CPU(STW),對(duì)并發(fā)標(biāo)記階段用戶線程運(yùn)行產(chǎn)生的垃圾對(duì)象進(jìn)行標(biāo)記修正
并發(fā)清除(CMS concurrent sweep)可以和用戶線程并行執(zhí)行,清理垃圾
其中,初始標(biāo)記、重新標(biāo)記這兩個(gè)步驟仍然需要Stop-the-world。初始標(biāo)記僅僅只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象,速度很快,并發(fā)標(biāo)記階段就是進(jìn)行GC Roots Tracing的過(guò)程,而重新標(biāo)記階段則是為了修正并發(fā)標(biāo)記期間因用戶程序繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記錄,這個(gè)階段的停頓時(shí)間一般會(huì)比初始階段稍長(zhǎng)一些,但遠(yuǎn)比并發(fā)標(biāo)記的時(shí)間短。
并發(fā)收集、低停頓
1)對(duì)CPU非常敏感:在并發(fā)階段雖然不會(huì)導(dǎo)致用戶線程停頓,但是會(huì)因?yàn)檎加昧艘徊糠志€程使應(yīng)用程序變慢
2)無(wú)法處理浮動(dòng)垃圾:在最后一步并發(fā)清理過(guò)程中,用戶線程執(zhí)行也會(huì)產(chǎn)生垃圾,但是這部分垃圾是在標(biāo)記之后,所以只有等到下一次gc的時(shí)候清理掉,這部分垃圾叫浮動(dòng)垃圾
3)CMS使用“標(biāo)記-清理”法會(huì)產(chǎn)生大量的空間碎片:當(dāng)碎片過(guò)多,將會(huì)給大對(duì)象空間的分配帶來(lái)問(wèn)題,會(huì)出現(xiàn)老年代還有很大的空間但無(wú)法找到足夠大的連續(xù)空間來(lái)分配當(dāng)前對(duì)象,不得不提前觸發(fā)一次FullGC,為了解決這個(gè)問(wèn)題CMS提供了一個(gè)開(kāi)關(guān)參數(shù)(-XX:+UseCMSCompactAtFullCollection默認(rèn)開(kāi)啟),用于在FullGC完成之后進(jìn)行一次碎片整理,但是內(nèi)存整理的過(guò)程是無(wú)法并發(fā)的,會(huì)導(dǎo)致停頓時(shí)間變長(zhǎng)
年輕代垃圾回收只會(huì)回收Eden區(qū)和Survivor區(qū)。YGC時(shí),首先G1停止應(yīng)用程序的執(zhí)行(Stop-The-World),G1創(chuàng)建回收集(Collection Set),回收集是指需要被回收的內(nèi)存分段的集合,年輕代回收過(guò)程的回收集包含年輕代Eden區(qū)和Survivor區(qū)所有的內(nèi)存分段。
1)第一階段,掃描根。根是指static變量指向的對(duì)象,正在執(zhí)行的方法調(diào)用鏈條上的局部變量等。跟引用連同RSet記錄的外部引用作為掃描存活對(duì)象的入口。
2)第二階段,更新RSet。處理dirty card queue中的card,更新RSet。此階段完成后,RSet可以準(zhǔn)確的反映老年代對(duì)所在的內(nèi)存分段中對(duì)象的引用。
3)第三階段,處理RSet。識(shí)別被老年代對(duì)象指向的Eden中的對(duì)象,這些被指向的Eden中的對(duì)象被認(rèn)為是存活的對(duì)象。
4)第四階段,復(fù)制對(duì)象。此階段,對(duì)象樹(shù)被遍歷,Eden區(qū)內(nèi)存段中存活的對(duì)象會(huì)被復(fù)制到Survivor區(qū)中空的內(nèi)存分段,Survivor區(qū)內(nèi)存段中存活的對(duì)象如果年齡未達(dá)閾值,年齡會(huì)加1,達(dá)到閾值會(huì)被復(fù)制到Old區(qū)中空的內(nèi)存分段。如果Survivor空間不夠,Eden空間的部分?jǐn)?shù)據(jù)會(huì)直接晉升到老年代空間。
5)第五階段,處理引用。處理Soft,Weak,Phantom,Final,JNI Weak 等引用。最終Eden空間的數(shù)據(jù)為空,GC停止工作,而目標(biāo)內(nèi)存中的對(duì)象都是連續(xù)存儲(chǔ)的,沒(méi)有碎片,所以復(fù)制過(guò)程可以達(dá)到內(nèi)存整理的效果,減少碎片。
當(dāng)整個(gè)堆大小在jvm堆棧空間中占比達(dá)到IHOP閾值-XX:InitiatingHeapOccupancyPercent(默認(rèn)45%)時(shí),G1就會(huì)啟動(dòng)一次混合垃圾收集周期。Mix GC不僅進(jìn)行正常的新生代垃圾收集,同時(shí)也回收部分后臺(tái)掃描線程標(biāo)記的老年代分區(qū)。進(jìn)行Mix GC之前,會(huì)先進(jìn)行全局并發(fā)標(biāo)記。
1)初始標(biāo)記(InitingMark):標(biāo)記GC Roots,會(huì)STW,一般會(huì)復(fù)用YoungGC的暫停時(shí)間。初始標(biāo)記會(huì)設(shè)置好所有分區(qū)的NTAMS值。
2)根分區(qū)掃描(RootRegionScan):根據(jù)初始標(biāo)記階段確定的GC根元素,掃描這些元素所在region,獲取對(duì)老年代的引用,并標(biāo)記被引用的對(duì)象。 該階段與應(yīng)用線程并發(fā)執(zhí)行,也就是說(shuō)沒(méi)有STW停頓,必須在下一次年輕代GC開(kāi)始之前完成。
3)并發(fā)標(biāo)記(ConcurrentMark):遍歷整個(gè)堆,查找所有可達(dá)的存活對(duì)象。若發(fā)現(xiàn)區(qū)域?qū)ο笾械乃袑?duì)象都是垃圾,那這個(gè)區(qū)域會(huì)被立即回收。 此階段與應(yīng)用線程并發(fā)執(zhí)行, 也允許被年輕代GC打斷。
4)最終標(biāo)記(Remark):此階段有一次STW暫停,以完成標(biāo)記周期。 G1會(huì)清空SATB緩沖區(qū),跟蹤未訪問(wèn)到的存活對(duì)象,并進(jìn)行引用處理。
5)清除階段(Clean UP): 這是最后的子階段,G1在執(zhí)行統(tǒng)計(jì)和清理RSet時(shí)會(huì)有一次STW停頓。 在統(tǒng)計(jì)過(guò)程中,會(huì)把完全空閑的region標(biāo)記出來(lái),也會(huì)標(biāo)記出適合于進(jìn)行混合模式GC的候選region。 清理階段有一部分是并發(fā)執(zhí)行的,比如在重置空閑region并將其加入空閑列表時(shí)。
清除階段之后,還會(huì)對(duì)存活對(duì)象進(jìn)行轉(zhuǎn)移(復(fù)制算法),轉(zhuǎn)移到其他可用分區(qū),所以當(dāng)前的分區(qū)就變成了新的可用分區(qū)。復(fù)制轉(zhuǎn)移主要是為了解決分區(qū)內(nèi)的碎片問(wèn)題。
1)并發(fā)標(biāo)記結(jié)束以后,老年代中百分百為垃圾的內(nèi)存分段被回收了,部分為垃圾的內(nèi)存分段被計(jì)算了出來(lái)。默認(rèn)情況下,這些老年代的內(nèi)存分段會(huì)分8次(可以通過(guò)-XX:G1MixedGCCountTarget設(shè)置)被回收。
2)混合回收的回收集(Collection Set)包括八分之一的老年代內(nèi)存分段,Eden區(qū)內(nèi)存分段,Survivor區(qū)內(nèi)存分段。混合回收的算法和年輕代回收的算法完全一樣,只是回收集多了老年代的內(nèi)存分段。具體過(guò)程請(qǐng)參考年輕代回收過(guò)程。
3)由于老年代中的內(nèi)存分段默認(rèn)分8次回收,G1會(huì)優(yōu)先回收垃圾多的內(nèi)存分段。垃圾占內(nèi)存分段比例越高,越會(huì)被先回收。并且有一個(gè)閾值會(huì)決定內(nèi)存分段是否被回收。-XX:G1MixedGCLiveThresholdPercent,默認(rèn)為65%,意思是垃圾占內(nèi)存分段比例要達(dá)到65%才會(huì)被回收。如果垃圾占比太低,意味著存活的對(duì)象占比高,在復(fù)制的時(shí)候會(huì)花費(fèi)更多的時(shí)間。
4)混合回收并不一定要進(jìn)行8次。有一個(gè)閾值-XX:G1HeapWastePercent,默認(rèn)值為10%,意思是允許整個(gè)堆內(nèi)存中有10%的空間被浪費(fèi),意味著如果發(fā)現(xiàn)可以回收的垃圾占堆內(nèi)存的比例低于10%,則不再進(jìn)行混合回收。因?yàn)镚C會(huì)花費(fèi)很多的時(shí)間但是回收到的內(nèi)存卻很少。
1)并行與并發(fā):G1能充分利用多CPU、多核環(huán)境下的硬件優(yōu)勢(shì),使用多個(gè)CPU來(lái)縮短Stop-the-world停頓的時(shí)間,部分其他收集器原來(lái)需要停頓Java線程執(zhí)行的GC操作,G1收集器仍然可以通過(guò)并發(fā)的方式讓Java程序繼續(xù)運(yùn)行。
2)分代收集
3)空間整合:與CMS的標(biāo)記-清除算法不同,G1從整體來(lái)看是基于標(biāo)記-整理算法實(shí)現(xiàn)的收集器,從局部(兩個(gè)Region之間)上來(lái)看是基于“復(fù)制”算法實(shí)現(xiàn)的。但無(wú)論如何,這兩種算法都意味著G1運(yùn)作期間不會(huì)產(chǎn)生內(nèi)存空間碎片,收集后能提供規(guī)整的可用內(nèi)存。這種特性有利于程序長(zhǎng)時(shí)間運(yùn)行,分配大對(duì)象時(shí)不會(huì)因?yàn)闊o(wú)法找到連續(xù)內(nèi)存空間而提前觸發(fā)下一次GC。
4)可預(yù)測(cè)的停頓:這是G1相對(duì)于CMS的另一大優(yōu)勢(shì),降低停頓時(shí)間是G1和CMS共同的關(guān)注點(diǎn),但G1除了追求低停頓外,還能建立可預(yù)測(cè)的停頓時(shí)間模型,能讓使用這明確指定一個(gè)長(zhǎng)度為M毫秒的時(shí)間片段內(nèi),消耗在垃圾收集上的時(shí)間不得超過(guò)N毫秒。
到此,相信大家對(duì)“G1垃圾回收器與CMS的區(qū)別有哪些”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!