1. 到底是誰在回收 JVM 的垃圾~

        共 6367字,需瀏覽 13分鐘

         ·

        2021-04-02 10:28

        來源 |  星塵的一個(gè)朋友(ID:rushjava

        開往虛擬機(jī)的車已經(jīng)出發(fā),關(guān)注上車

        那些回收 JVM 垃圾的家伙
        ?

        虛擬機(jī)的垃圾回收器,沒有哪一個(gè)是絕對(duì)好的,只有比較好的。

        ?

        今天的這篇文章,我要與你分享虛擬機(jī)的那些垃圾回收器們。內(nèi)容不多,可以耐心看完。

        垃圾收集器

        之前我們已經(jīng)了解過具體的 GC 涉及的細(xì)節(jié)知識(shí)點(diǎn),現(xiàn)在我們站在更高的角度,來看看各種垃圾收集器,以及其中兩個(gè)的工作過程(CMS 和 G1)。
        我們知道,虛擬機(jī)將保存對(duì)象實(shí)例的區(qū)域分為了兩個(gè)叫做 「新生代」「老年代」 的地方,為此虛擬機(jī)針對(duì)不同的內(nèi)存區(qū)域利用不同的算法設(shè)計(jì)了不同的垃圾收集器。
        了解垃圾收集器之前,我覺得還是有必要在復(fù)習(xí)一下  「Stop The World」 ,其用來形容在安全點(diǎn)用戶線程暫停的這種狀態(tài)的一個(gè)叫法。關(guān)于這個(gè)垃圾收集器工作的時(shí)候?yàn)槭裁匆?Stop The World 還有一個(gè)比較有意思的事 ,“你媽媽在給你打掃房間的時(shí)候, 肯定也會(huì)讓你老老實(shí)實(shí)地在椅子上或者房間外待著, 如果她一邊打掃, 你一邊亂扔紙屑, 這房間還能打掃完? ”這是虛擬機(jī)團(tuán)隊(duì)對(duì) Stop The World 的說明,嗯,很有道理,哈哈哈。

        那些回收 JVM 垃圾的家伙

        Serial

        關(guān)鍵字:新生代、Stop The World 、標(biāo)記 - 復(fù)制算法、單線程

        Serial 是作用在新生代的垃圾收集器,單線程工作,在工作的時(shí)候需要 Stop The World,(包括之前提到的 GC 工作,都是指可達(dá)性分析)。采用的是標(biāo)記 - 復(fù)制算法,(關(guān)于標(biāo)記 - 復(fù)制的內(nèi)容之前有講過就不再展開說了)。
        看起來 Serial 收集器沒什么特別的,但實(shí)際上 Serial 收集器在一些特殊的場(chǎng)景下有著不錯(cuò)的表現(xiàn),這些要得益于他的額外內(nèi)存消耗,因?yàn)槠湎啾绕渌占饕∫恍?,所以在服?wù)器資源受限的情況下(單核或較少核心以及內(nèi)存緊張),這個(gè)簡(jiǎn)單的單線程收集器效率還是很可觀的。

        ParNew

        關(guān)鍵字:新生代、Stop The World 、標(biāo)記 - 復(fù)制算法、多線程、「絕配」

        ParNew 可以看成 new parallel gc ,一個(gè)新的并行垃圾收集器。是一個(gè)對(duì)標(biāo) Serial 的收集器,它與 Serial 的區(qū)別就是它在工作的時(shí)候是使用多線程進(jìn)行工作的。還有,它是目前(JDK 9 以后)「唯一一個(gè)」能配合 CMS 在新生代工作的垃圾收集器。

        Parallel Scavenge

        關(guān)鍵字:新生代、Stop The World、標(biāo)記 - 復(fù)制算法、多線程、可控吞吐量【用戶線程執(zhí)行時(shí)間 /(用戶線程執(zhí)行時(shí)間+GC線程執(zhí)行時(shí)間)】、「自適應(yīng)策略」

        與 ParNew 相比,Parallel Scavenge 多了一些額外的功能,停頓時(shí)間和吞吐量可控(通過參數(shù)配置-XX:MaxGCPauseMillis  單位毫秒,控制每次垃圾回收的最大停頓時(shí)間。-XX:GCTimeRatio  控制吞吐量 0 - 100 整數(shù),1/(1+設(shè)置的參數(shù)) = 垃圾收集時(shí)間占程序執(zhí)行的總時(shí)間比率。
        對(duì)于 Parallel Scavenge 還有一個(gè)特點(diǎn),就是自適應(yīng)策略,把內(nèi)存管理工作完全交由虛擬機(jī),通過參數(shù) -XX:+UseAdaptiveSizePolicy  啟用自適應(yīng)內(nèi)存策略,這樣就不需要指定內(nèi)存參數(shù),比如新生代大小、eden survivor 比例 晉升年齡等參數(shù)。虛擬機(jī)會(huì)根據(jù)當(dāng)前系統(tǒng)運(yùn)行狀態(tài)動(dòng)態(tài)的調(diào)整,達(dá)到一個(gè)合適的停頓時(shí)間和吞吐量。

        上面這三種 「Serial」  、 「ParNew」  、 「Parallel Scavenge」 都是新生代的垃圾收集器,下面我們來看看老年代的垃圾收集器。

        Serial Old

        關(guān)鍵字:老年代、Stop The World、標(biāo)記 - 整理算法、單線程、「替補(bǔ)」

        Serial Old 是和 Serial 一樣的一款收集器,只不過,它是工作在老年代的。換句話說就是 Serial Old 就是 Serial 的老年代版本。Serial Old 有一個(gè)特殊的用途就是作為 CMS 并發(fā)清除失敗的時(shí)候的替補(bǔ),這里后面 CMS 收集器再看。

        Parallel Old

        關(guān)鍵字:老年代、Stop The World、標(biāo)記 - 整理算法、多線程、CP(組合)

        Parallel Old 是一個(gè)多線程并行的老年代垃圾收集器。它的出現(xiàn)也是為了解決吞吐量最大化的問題。因?yàn)樗麤]出現(xiàn)之前,只有 Serial Old 一款老年代垃圾收集器來配合 Parallel Scavenge ,因?yàn)?Serial Old 的單線程性能原因,導(dǎo)致 Parallel Scavenge 吞吐量的優(yōu)勢(shì)體現(xiàn)不出來。直到它的出現(xiàn),它與 Paralle Scavenge 就組成了一對(duì)完美的吞吐量 CP。

        CMS

        關(guān)鍵字:老年代、Stop The World、標(biāo)記 - 清除算法、多線程、短停頓

        Concurrent Mark Sweep 的設(shè)計(jì)初衷就是要停頓的時(shí)間最短!JDK 5 開始使用,JDK 9 以前最優(yōu)秀,為啥是 JDK 9 以前最優(yōu)秀,因?yàn)?JDK 9 發(fā)布的時(shí)候,默認(rèn)啟用了 G1 收集器,同時(shí)你如果手動(dòng)改成 CMS 的話,會(huì)受到一個(gè) CMS 被聲明為不推薦的警告,下面是它具體的工作過程,一共經(jīng)歷 4 個(gè)階段

        具體步驟如下:

        • 初始標(biāo)記:需要 Stop The World
        • 標(biāo)記 GC Roots 直接關(guān)聯(lián)的對(duì)象(直達(dá)),速度較快,停頓時(shí)間短。

        • 并發(fā)標(biāo)記與用戶線程并發(fā)
        • 進(jìn)行標(biāo)記追蹤,完成全部對(duì)象的標(biāo)記任務(wù)??赡艹霈F(xiàn)漏標(biāo)或錯(cuò)標(biāo)情況。

        • 重新標(biāo)記:需要 Stop The World
        • 修正并發(fā)標(biāo)記階段的對(duì)象標(biāo)記,因?yàn)榇蟛糠謱?duì)象不需要修正,所以執(zhí)行時(shí)間相比并發(fā)標(biāo)記時(shí)間短,但是停頓時(shí)間要比初始標(biāo)記停頓時(shí)間長(zhǎng)。

        • 并發(fā)清除與用戶線程并發(fā)
        • 耗時(shí)較長(zhǎng),可以與用戶線程共同工作。

        CMS 雖然有了一個(gè)較短的停頓時(shí)間,但是也有一些其他隨之而來的問題。

        優(yōu)點(diǎn)

        • 并發(fā)執(zhí)行速度快、停頓時(shí)間短。這一點(diǎn)沒得說,因?yàn)樗渲杏袃蓚€(gè)階段是和用戶線程并發(fā)。

        缺點(diǎn)

        • 「占用線程資源」,因?yàn)?CMS 工作有兩個(gè)階段是和用戶線程并發(fā),所以這里便會(huì)搶占用戶線程資源。
        • 「浮動(dòng)垃圾」,清理一次之后還會(huì)有清理不掉的對(duì)象,需要在下次清理的時(shí)候才能夠清理到。
        • 這里的原因是因?yàn)椴l(fā)清除階段是和用戶線程并發(fā),一邊清除一邊使用,可能會(huì)出現(xiàn)一些無法清理掉的新生垃圾,比如清理過程中,程序斷開了某個(gè)引用,被斷開的引用 GC Roots 不可達(dá),所以這個(gè)被斷開的引用指向的對(duì)象變成了浮動(dòng)垃圾。

        • 「空間利用率低」,因?yàn)椴l(fā)清理的原因,所以不能等到內(nèi)存完全用完之后再做清理,所以需要當(dāng)內(nèi)存使用達(dá)到一定閾值(默認(rèn)值68%,JDK6的時(shí)候提高到了 92%)時(shí)就開始進(jìn)行垃圾回收動(dòng)作,具體數(shù)值可以通過參數(shù)控制。
        • 這里 JVM 給了風(fēng)險(xiǎn)預(yù)案:凍結(jié)用戶線程,啟動(dòng) serial old 來進(jìn)行一次老年代垃圾回收。這也是上面我們說 Serial Old 的時(shí)候,提到他的關(guān)鍵字里有 “替補(bǔ)” 的原因。

        • 「空間碎片」,因?yàn)槭褂脴?biāo)記-清除算法的原因,會(huì)導(dǎo)致碎片空間的產(chǎn)生。CMS 的做法是在其不能夠滿足對(duì)象分配任務(wù)的時(shí)候,F(xiàn)ULL GC 的時(shí)候,會(huì)進(jìn)行一次空間整理的動(dòng)作。

          對(duì)這個(gè)整理的動(dòng)作也是有參數(shù)可以進(jìn)行控制,參數(shù)設(shè)置情況為,滿足幾次FullGC之后,進(jìn)行一次空間整理,默認(rèn)值為 0 ,即每次 full gc 都會(huì)進(jìn)行一次空間整理。

          這一點(diǎn)雖然是缺點(diǎn),不過 CMS 已經(jīng)盡力去彌補(bǔ)了,包括這里的 FULL GC 之后的內(nèi)存空間整理,還有對(duì)象分配時(shí) CMS 會(huì)在 Free List 申請(qǐng)一塊較大的內(nèi)存空間,然后通過指針碰撞的方式來進(jìn)行對(duì)象分配,盡可能減小空間碎片的產(chǎn)生。

          空間碎片問題也是 CMS 不能直接使用指針碰撞的方式來為對(duì)象分配內(nèi)存的原因。

        Garbage First (G1)

        關(guān)鍵字:里程碑、JDK 9、區(qū)域管理、按需回收、「延遲可控的最高吞吐量」

        要說 CMS 是一個(gè)劃時(shí)代收集器,那 G1 可以稱得上劃時(shí)代的劃時(shí)代收集器,其作為 JVM 的垃圾收集器的里程碑是有一定原因的,我們繼續(xù)往下看。
        G1 出現(xiàn)的原因也很簡(jiǎn)單,那就是替換掉 CMS 。G1的設(shè)計(jì)是顛覆性的設(shè)計(jì)思路,它跳出了內(nèi)存一定要?jiǎng)澐中律夏甏倪@個(gè)枷鎖,它的工作模式為 Mixed Mode。并且 JDK 9 的時(shí)候開始啟用,成為了服務(wù)端模式下的默認(rèn)垃圾收集器,替換掉了原來的吞吐量組合(Parallel Scavenge + Parallel Old),同時(shí) CMS 被聲明為不推薦使用,CMS 也是從JDK 9 開始準(zhǔn)備退役。
        按需回收說的是 G1 在做清理的時(shí)候,是依據(jù)一個(gè)「可預(yù)測(cè)停頓時(shí)間模型」來做的,這是個(gè)什么東西呢?簡(jiǎn)單來說就是,在清理之前,G1 對(duì)每個(gè)待回收的區(qū)域根據(jù)回收價(jià)值和時(shí)間進(jìn)行排序,然后根據(jù)用戶所期望的停頓時(shí)間來做一個(gè)最優(yōu)回收,后面會(huì)繼續(xù)說。
        ?

        多了解一點(diǎn),關(guān)于 G1 的工作模式,Mixed Mode  的擴(kuò)展:G1 有純 GC 模式和分代回收模式,分代模式會(huì)分為 Minor GC 和 Mixed GC 兩種,這里的模式選擇會(huì)影響最后的篩選回收階段的回收集合的內(nèi)容。這塊內(nèi)容可參考后面留的 R大 的鏈接

        ?
        上面有一點(diǎn)展開說一下,就是 G1 不是沒有分代這種操作了嗎?是通過內(nèi)存區(qū)域來管理垃圾的,但是事實(shí)上 G1 將內(nèi)存分成多個(gè)大小相等的 Region(區(qū)域) ,這些 Region 都可以作為Eden、Survivor、Humongous(Humongous 同老年代的作用)。

        下面我們一起了解一下 G1 工作的具體步驟:

        • 初始標(biāo)記Stop The World
        • 標(biāo)記 GC Roots 直接關(guān)聯(lián)的對(duì)象,同時(shí)修改 TAMS 指針

        • 并發(fā)標(biāo)記與用戶線程并發(fā)
        • 標(biāo)記全部要回收的對(duì)象,與用戶線程并發(fā),標(biāo)記完成之后,重新處理 SATB 記錄下在并發(fā)時(shí)有引用變動(dòng)的對(duì)象

        • 最終標(biāo)記Stop The World
        • 處理并發(fā)標(biāo)記階段 SATB 遺留的引用,同時(shí)這個(gè)階段也進(jìn)行弱引用處理。

        • 篩選回收Stop The World
        • 這個(gè)階段會(huì)更新 Region 的統(tǒng)計(jì)數(shù)據(jù),對(duì)每個(gè) Region 根據(jù)其回收價(jià)值和成本進(jìn)行排序,然后根據(jù)用戶所期望的停頓時(shí)間(參數(shù)設(shè)置)來制定一個(gè)回收計(jì)劃。

          再根據(jù)這個(gè)計(jì)劃,選擇任意 Region 來組成一個(gè)回收集(collection set)。將回收集中的 Region(被選中的區(qū)域) 中的存活對(duì)象復(fù)制到空的 Region 中,然后將舊的(選中的) Region 清理掉。

          以上過程由多線程并行完成,同時(shí)因?yàn)橐苿?dòng)對(duì)象需要暫停用戶線程(Stop The World)

        ?

        TAMS:Top at Mark Start   Region 中的兩個(gè)指針名稱,他們的作用是將 Region 的一部分空間劃分出來給并發(fā)回收過程中程序運(yùn)行產(chǎn)生的新對(duì)象使用

        SATB:原始快照,還記得之前我們對(duì)漏標(biāo)的解決方案嗎?一種是增量更新(CMS 采用的這種方案),另外一個(gè)就是原始快照,這里可以翻翻之前的內(nèi)容。

        ?

        G1除了并發(fā)標(biāo)記階段都需要暫停用戶線程

        G1的理想目標(biāo):在延遲可控的情況下達(dá)到最大的吞吐量

        用戶可以通過參數(shù)設(shè)置所期望的停頓時(shí)間,這個(gè)時(shí)間一般建議設(shè)置為 100 ~ 300 ms。

        垃圾收集器小結(jié)

        上面一共說了 7 款垃圾收集器,不過他們的具體使用我覺得有必要了解一下。

        按照分工劃分

        「新生代」Serial、ParNew、Parallel Scavenge

        「老年代」Serial Old、Parallel Old、CMS

        內(nèi)存區(qū)域:G1

        按照搭配組合劃分

        因?yàn)椴煌碾A段,垃圾收集器之間的搭配不同,所以我們就按照 JDK 9 作為劃分界線,來看下 JDK 9 前后的搭配情況
        搭配方案-JDK9之前
        搭配方案-JDK9以后
        通過搭配關(guān)系我們可以看出,JDK 9 以前,Hotspot 提供了多種選擇,而且場(chǎng)面看起來很和諧,解釋一下 CMS 與 Serial Old 之間的虛線,這代表 CMS 并發(fā)清除失敗的時(shí)候,以 Serial Old 作為備選方案的組合。
        JDK 9 之后,因?yàn)?G1 的出現(xiàn),hotspot 取消了兩種方案的支持(Serial + CMS 和 ParNew + CMS),僅提供了 4 種虛擬機(jī)搭配方案,他們分別是
        • Serial + Serial Old  的單線程組合,適用于資源受限的場(chǎng)景。
        • ParNew + CMS 這組曾經(jīng)的王者組合,新生代的多線程并行高性能加上老年代的短暫停頓組合,可以應(yīng)對(duì)大部分場(chǎng)景。
        • Parallel Scavenge + Serial Old 這是 Paralle Old 沒出現(xiàn)的時(shí)候的應(yīng)對(duì)組合(不明白為何 JDK 9 的時(shí)候沒取消這對(duì)奇葩組合)
        • Parallel Scavenge + Parallel Old 這對(duì)高吞吐量 CP

        G1的出現(xiàn)

        看起來這 4 組搭配很完美,不過因?yàn)?G1 的出現(xiàn),看起來的美好也沒那么好了 G1在 server 模式下取代了高吞吐量的 CP (Parallel Scavenge + Parallel Old)成為了默認(rèn)的垃圾收集器。
        同時(shí)在 JDK 9 使用 ParNew + CMS 這組搭配時(shí),還會(huì)收到來自 hotspot 的警告,CMS 已經(jīng)被聲明為不推薦使用,因?yàn)?ParNew 此時(shí)只能與 CMS 搭配使用,所以可以說當(dāng)時(shí) CMS 拯救了 ParNew 的尷尬局面(當(dāng)時(shí)新生代高性能的 ParNew 只能選擇拖后腿的 Serial Old 一起工作),現(xiàn)在 ParNew 也要陪著 CMS 一起下崗了。

        現(xiàn)狀

        綜上所述,到 JDK 9 之后還剩下建議使用的組合如下

        • G1
        • Serial + Serial Old
        • Parallel Scavenge + Serial Old (還是它,我一定要關(guān)注它倆啥時(shí)候下崗)

        所以通過上面的分析,也能看出來 HotSpot 的用意,在 JDK 9 以后就是要將 G1 作為一個(gè)全能型的垃圾收集器來發(fā)展。

        寫在最后

        上面總結(jié)了截止 JDK 9 的垃圾收集器內(nèi)容,其實(shí)對(duì)于垃圾收集器還有很多內(nèi)容,比如 Shenandoah ,一個(gè)由 Red Hat 開發(fā)的低延遲垃圾收集器,還有 Oracle 后面的 ZGC。這兩個(gè)垃圾收集器都采用了更加優(yōu)秀的思想和實(shí)現(xiàn)方案。不過因?yàn)槲覜]有對(duì)其深入的了解,所以在這就不再多說了。如果你對(duì)垃圾收集器的內(nèi)容仍感興趣,推薦訪問下面這個(gè)鏈接,R大 寫的虛擬機(jī)相關(guān)內(nèi)容

        https://www.iteye.com/blog/rednaxelafx-362738


        1、阿里云盤正式公測(cè)!免費(fèi)領(lǐng)1年云盤擴(kuò)容碼,速來,先到先得!
        2、牛逼!IntelliJ IDEA居然支持視頻聊天了~速來嘗鮮!快來沖一波
        3、如何設(shè)置最近爆火的微信開關(guān)頭像?想學(xué)啊,我教你啊~
        4、知名國產(chǎn)網(wǎng)盤翻車?清空免費(fèi)用戶文件后,又開始清理付費(fèi)用戶資源
        5、Chrome新功能曝光:你訪問的敏感網(wǎng)站可以自動(dòng)隱藏起來
        6、萬萬沒想到,“紅孩兒”竟然做了程序員,還是CTO!
        7、徒手?jǐn)]一個(gè)Spring Boot中的starter,解密自動(dòng)化配置,超級(jí)棒!

        點(diǎn)分享

        點(diǎn)收藏

        點(diǎn)點(diǎn)贊

        點(diǎn)在看

        瀏覽 47
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 操黑丝 | 欧美性爱视频一区二区三区 | 在线免费观看成人网站 | 边打电话边被躁91 | 羞羞草视频 |