Java垃圾回收(4)
G1:垃圾優(yōu)先
G1收集器是熱點(diǎn)JVM中要實(shí)現(xiàn)的最新收集器。 自Java 7 Update 4以來(lái),它一直是受支持的收集器。OracleGC團(tuán)隊(duì)也公開(kāi)表示,他們對(duì)低暫停GC的希望是完全實(shí)現(xiàn)的G1。 這篇文章來(lái)自我之前的垃圾收集博客文章:
問(wèn)題:大堆意味著長(zhǎng)暫停時(shí)間
并發(fā)標(biāo)記和掃描(CMS)收集器是當(dāng)前推薦的低暫停收集器,但是不幸的是,其暫停時(shí)間隨使用權(quán)區(qū)域中活動(dòng)對(duì)象的數(shù)量而定。 這意味著,盡管使用較小的堆獲得較短的GC暫停相對(duì)容易,但是一旦開(kāi)始使用10或100千兆字節(jié)的堆,時(shí)間就會(huì)開(kāi)始增加。
CMS也不會(huì)“整理”其堆,因此在某個(gè)時(shí)間點(diǎn)您會(huì)遇到并發(fā)模式故障(CMF),從而觸發(fā)完整的gc。 一旦進(jìn)入了完整的gc場(chǎng)景,您就可以預(yù)期每千兆字節(jié)活動(dòng)對(duì)象大約1秒鐘的時(shí)間間隔。 使用CMS,您的100GB堆可能是等待1.5分鐘的GC暫停滴答定時(shí)炸彈……
良好的GC調(diào)優(yōu)可以解決此問(wèn)題,但有時(shí)只會(huì)將問(wèn)題推向前進(jìn)。 并發(fā)模式失敗和完整GC不可避免地會(huì)在足夠長(zhǎng)的時(shí)間范圍內(nèi)出現(xiàn),除非您處在一小部分專門(mén)避免填充其使用期限的人員中。
G1堆布局
G1收集器試圖通過(guò)將堆分成不同的區(qū)域來(lái)將單個(gè)集合的暫停時(shí)間與堆的整體大小分開(kāi)。 每個(gè)區(qū)域的大小都是固定的,介于1MB和32MB之間,JVM的目標(biāo)是總共創(chuàng)建大約2000個(gè)區(qū)域。
您可能還記得以前的文章,其他收集器將堆分為Eden,Survior Space和Tenured內(nèi)存池。 G1保留相同類別的池,但不是將它們作為連續(xù)的內(nèi)存塊,而是將每個(gè)區(qū)域在邏輯上分類為這些池之一。
還有另一種類型的區(qū)域-大型區(qū)域。 這些對(duì)象用于存儲(chǔ)大小比大多數(shù)對(duì)象大的對(duì)象,例如,很長(zhǎng)的數(shù)組。 任何大于區(qū)域大小50%的對(duì)象都存儲(chǔ)在巨大的區(qū)域中。 它們通過(guò)獲取連續(xù)位于內(nèi)存中的多個(gè)普通區(qū)域并將它們視為單個(gè)邏輯區(qū)域來(lái)工作。
記憶集
當(dāng)然,如果您將不得不掃描整個(gè)堆以找出哪些對(duì)象被標(biāo)記為活動(dòng)對(duì)象,那么將堆分成多個(gè)區(qū)域毫無(wú)意義。 實(shí)現(xiàn)此目標(biāo)的第一步是將區(qū)域分成稱為卡的512字節(jié)段。 每張卡在卡標(biāo)記表中都有一個(gè)1字節(jié)的條目。
每個(gè)區(qū)域都有一個(gè)關(guān)聯(lián)的記憶集或RSet-這是已寫(xiě)入的卡集。 如果卡片中存儲(chǔ)的另一個(gè)區(qū)域中的某個(gè)對(duì)象指向該區(qū)域中的某個(gè)對(duì)象,則該卡片在記憶集中。
每當(dāng)更改器寫(xiě)入對(duì)象引用時(shí),就會(huì)使用寫(xiě)屏障來(lái)更新所記住的集合。 在幕后,記住的集合被分為不同的集合,以便不同的線程可以在沒(méi)有爭(zhēng)用的情況下運(yùn)行,但是從概念上講,所有集合都是同一集合的一部分。
并發(fā)標(biāo)記
為了標(biāo)識(shí)哪些堆對(duì)象是活動(dòng)的,G1執(zhí)行活動(dòng)對(duì)象的大部分并發(fā)標(biāo)記。
- 標(biāo)記階段標(biāo)記階段的目標(biāo)是弄清楚堆中哪些對(duì)象是活動(dòng)的。 為了存儲(chǔ)哪些對(duì)象處于活動(dòng)狀態(tài),G1使用了標(biāo)記位圖-堆中每64位存儲(chǔ)一個(gè)位。 從所有對(duì)象的根部開(kāi)始跟蹤,并在標(biāo)記位圖中使用活動(dòng)對(duì)象標(biāo)記區(qū)域。 這通常是并發(fā)的,但是有一個(gè)類似于CMS的“ 初始標(biāo)記暫停” ,其中應(yīng)用程序被暫停并且跟蹤根對(duì)象的第一級(jí)子級(jí)。 完成此步驟后,重新啟動(dòng)線程。 G1需要保持對(duì)堆中生活內(nèi)容的最新了解,因?yàn)椴粫?huì)在標(biāo)記階段的同一暫停中清理堆。
- 標(biāo)記階段標(biāo)記階段的目標(biāo)是使標(biāo)記階段中有關(guān)活動(dòng)對(duì)象的信息保持最新。 首先要做的是確定何時(shí)進(jìn)行標(biāo)記。 由一定百分比的堆已滿觸發(fā)。 這是通過(guò)從標(biāo)記階段和此后的分配數(shù)量中獲取信息來(lái)計(jì)算的,并告訴G1其是否超過(guò)了要求的百分比。 G1使用前面提到的寫(xiě)屏障來(lái)記錄對(duì)堆的更改,并將其存儲(chǔ)在一系列更改緩沖區(qū)中 。 更改緩沖區(qū)中的對(duì)象同時(shí)在標(biāo)記位圖中標(biāo)記。 當(dāng)達(dá)到填充百分比時(shí),將再次暫停更改程序線程并處理更改緩沖區(qū),從而將更改緩沖區(qū)中的對(duì)象標(biāo)記為活動(dòng)狀態(tài)。
- 清理階段此時(shí),G1知道哪些對(duì)象處于活動(dòng)狀態(tài)。 由于G1專注于可用空間最大的區(qū)域,因此下一步是通過(guò)對(duì)活動(dòng)對(duì)象進(jìn)行計(jì)數(shù)來(lái)計(jì)算給定區(qū)域中的可用空間。 這是從標(biāo)記位圖計(jì)算得出的,并且根據(jù)最有可能收集到哪些區(qū)域來(lái)對(duì)區(qū)域進(jìn)行排序。 要收集的區(qū)域存儲(chǔ)在所謂的收集集或CSet中 。
疏散
與半球年輕一代在并行GC和CMS收集器中采用的方法類似,不會(huì)收集死物。 取而代之的是,將有生命的物體從某個(gè)區(qū)域撤離,然后將整個(gè)區(qū)域視為空閑區(qū)域。
G1對(duì)于如何回收活動(dòng)物體很聰明–它不會(huì)嘗試在給定的周期內(nèi)回收所有活動(dòng)物體。 它針對(duì)的是可能會(huì)回收盡可能多空間的區(qū)域,僅將其撤離。 它通過(guò)計(jì)算活動(dòng)對(duì)象在一個(gè)區(qū)域內(nèi)的比例并選擇活動(dòng)對(duì)象比例最低的區(qū)域來(lái)確定其目標(biāo)區(qū)域。
將物體從多個(gè)其他區(qū)域撤離到自由區(qū)域。 這意味著G1在執(zhí)行GC時(shí)會(huì)壓縮數(shù)據(jù)。 這由多個(gè)線程并行操作。 傳統(tǒng)的“平行GC”可以做到這一點(diǎn),而CMS不這樣做。
與CMS和Parallel GC相似,存在終身制的概念。 也就是說(shuō),如果年輕對(duì)象在足夠的收藏中存活下來(lái),它們就會(huì)變“舊”。 此數(shù)字稱為任職期限。 如果年輕的世代區(qū)域在任職期限內(nèi)幸免,并保留了足夠的活物以避免被疏散,則該區(qū)域?qū)⒌玫教嵘?首先是幸存者,最后是終身制地區(qū)。 它從未被疏散。
疏散失敗
不幸的是,G1仍然會(huì)遇到類似于并發(fā)模式故障的情況,在這種情況下,它會(huì)退回到Stop the World Full GC。 這稱為疏散失敗,在沒(méi)有空閑區(qū)域時(shí)發(fā)生。 沒(méi)有自由區(qū)域意味著沒(méi)有地方疏散物體。
理論上,與CMS中的并發(fā)模式故障相比,G1中發(fā)生疏散失敗的可能性較小。 這是因?yàn)镚1會(huì)即時(shí)壓縮其區(qū)域,而不僅僅是等待壓縮失敗。
結(jié)論
盡管進(jìn)行了壓縮和在低暫停時(shí)做出的努力,但G1并不能保證一定會(huì)獲勝,采用它的任何嘗試都應(yīng)伴隨有客觀且可衡量的性能目標(biāo)以及GC Log分析。 所需的方法超出了本博客文章的范圍,但希望我會(huì)在以后的文章中介紹它。
從算法上講,G1會(huì)遇到其他Hotspot收集器不會(huì)遇到的開(kāi)銷。 值得注意的是,維護(hù)記憶集的成本。 并行GC仍然是推薦的吞吐量收集器,并且在許多情況下CMS都比G1更好。
現(xiàn)在說(shuō)G1是否會(huì)比CMS收集器大勝還為時(shí)過(guò)早,但是在某些情況下,它已經(jīng)為使用它的開(kāi)發(fā)人員提供了好處。 隨著時(shí)間的流逝,我們將看到G1的性能限制是否真的是G1的限制,或者開(kāi)發(fā)團(tuán)隊(duì)是否僅需要更多的工程工作來(lái)解決那里的問(wèn)題。
感謝John Oliver , Tim Monks和Martijn Verburg審閱了本期及以前的GC文章的草稿。
翻譯自: https://www.javacodegeeks.com/2013/07/garbage-collection-in-java-4.html
總結(jié)
以上是生活随笔為你收集整理的Java垃圾回收(4)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 资金流是什么意思 资金流介绍
- 下一篇: GlassFish 4带来了Java E