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