Java 虛擬機(jī)垃圾收集器(1)— 經(jīng)典垃圾收集器

前言

沒有完美的垃圾收集器,只有最適合具體應(yīng)用的垃圾收集器蹬蚁。

1. Serial 收集器

新生代收集器打月,最基礎(chǔ)且歷史最悠久的收集器,在 JDK 1.3.1 之前是 HotSpot 的唯一選擇湿硝。

工作圖

圖1. Serial 收集器(前)和 Serial Old(后)收集器運(yùn)行示意圖

參數(shù)

-XX:SurvivorRatio
Eden 區(qū)與 Survivor 區(qū)的比例薪前。
-XX:PretenureSizeThreshold
晉升老年代對象大小。

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

  • 足夠簡單关斜,額外內(nèi)存消耗最少
  • 在單核處理器或處理器核心較少時(shí)示括,單線程收集效率最高

缺點(diǎn)

  • 單線程 收集器
  • 進(jìn)行垃圾收集時(shí),必須暫停其他所有工作線程

使用場景

  • 單核處理器或處理器核心較少
  • 運(yùn)行在客戶端模式
  • 內(nèi)存資源受限

2. ParNew 收集器

新生代收集器痢畜,使用標(biāo)記 — 復(fù)制算法垛膝,實(shí)質(zhì)上為 Serial 收集器的多線程并行版本鳍侣。其控制參數(shù)、收集算法吼拥、暫停線程倚聚、對象分配規(guī)則和回收策略等都與 Serial 收集器一致,它們的實(shí)現(xiàn)代碼也有相當(dāng)多共用部分凿可。

JDK 7 以前惑折,它是不少運(yùn)行在服務(wù)端模式下的 HotSpot 虛擬機(jī)首選的新生代收集器。
JDK 9 以前枯跑,只有 Serial 和 ParNew 能與 CMS 收集器配合工作惨驶,JDK 9 開始 ParNew 只能和 CMS 收集器綁定使用。

工作圖

圖2. ParNew(前)和 Serial Old(后)收集器運(yùn)行示意圖

參數(shù)

同 Serial 收集器

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

  • 支持多線程并行收集

缺點(diǎn)

  • 進(jìn)行垃圾收集時(shí)敛助,必須暫停其他所有工作線程

3. Parallel Scavenge 收集器

新生代收集器粗卜,使用標(biāo)記 — 復(fù)制算法,和 ParNew 收集器一樣支持多線程并行收集辜腺,但 Parallel Scavenge 收集器更關(guān)注吞吐量休建,即 處理器用于運(yùn)行用戶代碼的時(shí)間 / 處理器總消耗時(shí)間,此處總消耗時(shí)間為 運(yùn)行用戶代碼的時(shí)間 + 運(yùn)行垃圾收集時(shí)間评疗。

停頓時(shí)間越短测砂,越適合需要與用戶交互或需要保證服務(wù)響應(yīng)質(zhì)量的程序。
吞吐量越高百匆,處理器資源利用率越高砌些,越快完成程序的運(yùn)算任務(wù),適合不需要太多交互的后臺運(yùn)算加匈、分析任務(wù)存璃。

參數(shù)

-XX:MaxGCPauseMilliis
最大垃圾收集停頓時(shí)間,大于 0 的毫秒數(shù)雕拼。值不宜過小纵东,會導(dǎo)致新生代空間縮小,以換取更短停頓時(shí)間啥寇,進(jìn)一步導(dǎo)致更頻繁的 GC偎球,吞吐量下降。
-XX:GCTimeRatio
吞吐量大小辑甜。值為吞吐量的倒數(shù)衰絮,即垃圾收集時(shí)間占總時(shí)間的比率。
-XX:+UseAdaptiveSizePolicy
動態(tài)設(shè)置新生代大小磷醋、Eden 與 Survivor 區(qū)的比例猫牡、晉升老年代對象大小等參數(shù),提供最合適停頓時(shí)間或最大吞吐量邓线。

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

  • 支持多線程并行收集
  • 自適應(yīng)調(diào)節(jié)參數(shù)
  • 吞吐量相較于 ParNew 收集器更好

缺點(diǎn)

  • 進(jìn)行垃圾收集時(shí)淌友,必須暫停其他所有工作線程

工作圖

圖3. Parallel Scavenge(前)和 Serial Old(后)收集器運(yùn)行示意圖

4. Serial Old 收集器

老生代收集器煌恢,使用標(biāo)記 — 整理算法,Serial Old 是 Serial 收集器的老年代版本亩进,故也為單線程收集器症虑。

工作圖

圖4. Serial 收集器(前)和 Serial Old(后)收集器運(yùn)行示意圖

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

  • 足夠簡單,額外內(nèi)存消耗最少
  • 在單核處理器或處理器核心較少時(shí)归薛,單線程收集效率最高

缺點(diǎn)

  • 單線程 收集器
  • 進(jìn)行垃圾收集時(shí),必須暫停其他所有工作線程

使用場景

  • 單核處理器或處理器核心較少
  • 運(yùn)行在客戶端模式
  • JDK 5 及以前版本下匪蝙,與 Paraellel Scavenge 收集器搭配使用
  • 作為 CMS 收集器失敗時(shí)的后備預(yù)案

5. Parallel Old 收集器

老生代收集器主籍,使用標(biāo)記 — 整理算法,Parallel Old 是 Parallel Scavenge 收集器的老年代版本逛球,故也為多線程收集器千元。

出現(xiàn)于 JDK 6,結(jié)束了此前 Parallel Scavenge 收集器只能搭配 Serial Old 收集器使用的狀態(tài)颤绕。

工作圖

圖5. Parallel Scavenge 收集器(前)和 Parallel Old(后)收集器運(yùn)行示意圖

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

  • 支持多線程并行收集
  • 自適應(yīng)調(diào)節(jié)參數(shù)
  • 吞吐量相較于 ParNew 收集器更好

缺點(diǎn)

  • 進(jìn)行垃圾收集時(shí)幸海,必須暫停其他所有工作線程

使用場景

  • 注重吞吐量
  • 處理器資源不充足

6. CMS 收集器

老生代收集器,使用標(biāo)記 — 清除算法奥务,支持多線程并行收集物独,以最短回收停頓時(shí)間為目標(biāo)的收集器。CMS 收集器在 JDK 5 中發(fā)布氯葬。

工作圖

圖6. CMS 收集器運(yùn)行示意圖

工作流程

1. 初始標(biāo)記

僅標(biāo)記 GC Roots 能直接關(guān)聯(lián)到的對象挡篓,速度較快,但需要暫停用戶線程帚称。

2. 并發(fā)標(biāo)記

從 GC Roots 直接關(guān)聯(lián)對象開始遍歷整個(gè)對象圖的過程官研,耗時(shí)較長但不影響用戶線程運(yùn)行。采用 增量更新

3. 重新標(biāo)記

修正并發(fā)標(biāo)記期間闯睹,用戶線程運(yùn)行導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分對象的標(biāo)記記錄戏羽,速度略慢于初始標(biāo)記,但遠(yuǎn)快于并發(fā)標(biāo)記楼吃。

4. 并發(fā)清除

清理刪掉標(biāo)記階段判斷已經(jīng)死亡的對象始花,不需要移動存活對象,故可與用戶線程并發(fā)所刀。

參數(shù)

-XX:CMSInitiatingOccupancyFraction
CMS 觸發(fā)垃圾回收的內(nèi)存占用比閾值

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

  • 支持多線程并行收集
  • 停頓時(shí)間較短

缺點(diǎn)

  • 對處理器資源非常敏感
    CMS 默認(rèn)啟動的回收線程數(shù)為 (處理器核心數(shù)量 + 3) / 4衙荐。當(dāng)處理器核心數(shù)在四個(gè)及以上時(shí),只占用不超過 25% 的運(yùn)行資源浮创,且核心數(shù)越多忧吟,占用越低;但核心數(shù)不足四個(gè)時(shí)斩披,回收線程對用戶程序影響會變大溜族。
  • 會產(chǎn)生浮動垃圾讹俊,有可能出現(xiàn) 并發(fā)失敗,進(jìn)而執(zhí)行 Full GC煌抒,導(dǎo)致所有線程暫停
    并發(fā)清理階段仍劈,用戶線程并發(fā)執(zhí)行,會伴隨新的垃圾對象產(chǎn)生寡壮,但這部分垃圾出現(xiàn)在標(biāo)記之后贩疙,無法在此次垃圾收集中清理,故留到下一次垃圾收集中清理况既,此部分垃圾被稱為浮動垃圾这溅。
    在并發(fā)垃圾收集時(shí),用戶線程需要持續(xù)進(jìn)行棒仍,故需要預(yù)留足內(nèi)存空間給用戶線程使用悲靴,JDK 5 為 68%,偏保守莫其;JDK 6 為 92%癞尚,又略激進(jìn),直接導(dǎo)致面臨預(yù)留空間不足而導(dǎo)致并發(fā)失敗乱陡,并需要啟動 Serial Old 收集器進(jìn)行老年代垃圾收集浇揩,暫停用戶線程,造成更久的停頓時(shí)間蛋褥。
  • 空間碎片多
    空間碎片多是標(biāo)記 — 清除算法的通病临燃,這將導(dǎo)致大對象容易找不到足夠的空間進(jìn)行分配,從而觸發(fā)一次 Full GC烙心,造成停頓膜廊。

使用場景

  • 追求停頓時(shí)間短的 B/S 系統(tǒng)

7. Garbage First(G1)收集器

G1 收集器可面向堆內(nèi)存任何部分組成回收集進(jìn)行回收,不再局限于新生代還是老年代淫茵。是垃圾收集器技術(shù)史上里程碑式的成果爪瓜,JDK 7 Update 4 中正式商用。

G1 收集器基于 Region 堆內(nèi)存布局匙瘪,仍然是遵循分代收集理論設(shè)計(jì)铆铆,但 G1 不再以固定大小及數(shù)量劃分分代區(qū)域,而是分成多個(gè)獨(dú)立區(qū)域(Region)丹喻。每個(gè) Region 根據(jù)需要扮演新生代的 Eden 空間薄货、Survivor 空間或老年代空間,且 不需要連續(xù)碍论,G1 收集器會對不同的角色進(jìn)行不同策略的處理谅猾。

Region 中有一類特殊的 Humongous 區(qū)域,專門用來存儲大對象。G1 收集器對大對象的定義為:超過一個(gè) Region 容量一半的對象税娜。當(dāng)對象超過整個(gè) Region 容量的超級大對象坐搔,將會被存放在多個(gè)連續(xù)的 Humongous 區(qū)域中,Humongous 區(qū)域被 G1 收集器當(dāng)作老年代看待敬矩。

Region 是最小回收單元概行,每次回收的內(nèi)存空間都是 Region 大小的整數(shù)倍。因此弧岳,G1 能建立可預(yù)測的停頓時(shí)間模型凳忙,有計(jì)劃避免全區(qū)域垃圾收集(相當(dāng)于 Full GC)。G1 收集器會根據(jù)回收所獲得空間大小及所需時(shí)間的經(jīng)驗(yàn)值禽炬,后臺維護(hù)一個(gè)優(yōu)先級列表消略,根據(jù)用戶設(shè)定允許的收集停頓時(shí)間優(yōu)先處理收益最大的 Region,故 G1 不追求一次性清理完整個(gè)堆瞎抛,只需要保證收集速度跟得上對象分配速度。

設(shè)計(jì)思路

  • 局部收集
  • Region 內(nèi)存布局

內(nèi)存區(qū)域圖

圖7. Region 內(nèi)存分區(qū)示意圖

其中 E 為 Eden 區(qū)域却紧,S 為 Survivor 區(qū)域桐臊,H 為 Humongous 區(qū)域。

工作圖

圖8. G1 收集器運(yùn)行示意圖.png

工作原理

1. 跨 Region 引用對象的解決

G1 收集器中晓殊,每個(gè) Region 都會維護(hù)自己的記憶集断凶,像其他收集器的記憶集一樣,記憶集中記錄下對其他 Region 的指針巫俺,還會記錄別的 Region 對自己的指針认烁,并標(biāo)記這些指針在哪些卡頁范圍內(nèi),即為雙向卡表介汹。

G1 收集器的記憶集存儲結(jié)構(gòu)本質(zhì)上是一種哈希表却嗡,Key 是別的 Region 的起始地址,Value 為一個(gè)集合嘹承,存儲卡表的索引號窗价。

因記憶集比其他傳統(tǒng)收集器多很多,導(dǎo)致 G1 收集器有著更高的內(nèi)存負(fù)擔(dān)叹卷,根據(jù)經(jīng)驗(yàn)撼港,G1 至少需要 Java 堆容量 10% 到 20% 額外內(nèi)存維持收集器工作。

2. 收集線程和用戶線程的協(xié)調(diào)
  • 對象引用關(guān)系改變
    用戶線程改變對象引用關(guān)系時(shí)骤竹,必須保證不能打破原本的對象圖結(jié)構(gòu)帝牡,導(dǎo)致標(biāo)記錯(cuò)誤,G1 采用 原始快照 算法實(shí)現(xiàn)蒙揣。
  • 新對象創(chuàng)建
    G1 為每個(gè) Region 設(shè)計(jì)了兩個(gè)名為 TAMS 的指針靶溜,將 Region 中的一部分空間劃分出來用于并發(fā)回收過程中新對象分配,并發(fā)回收時(shí)新分配對象地址都必須在這兩個(gè)指針位置上鸣奔。G1 默認(rèn)在這個(gè)地址以上的對象是被隱式標(biāo)記過墨技,即默認(rèn)存活惩阶,不納入回收范圍。
  • Full GC
    當(dāng)內(nèi)存回收速度趕不上內(nèi)存分配速度時(shí)扣汪,G1 收集器和 CMS 收集器類似断楷,會凍結(jié)用戶線程執(zhí)行,進(jìn)行 Full GC 而產(chǎn)生停頓崭别。
3. 建立可靠的停頓預(yù)測模型

用戶通過 -XX:MaxGCPauseMillis 參數(shù)指定的停頓時(shí)間只意味著垃圾收集發(fā)生前的期望值冬筒。

G1 收集器停頓預(yù)測模型是以衰減均值為理論基礎(chǔ)實(shí)現(xiàn)的,在垃圾收集過程中茅主,G1 收集器會記錄每個(gè) Region 的回收耗時(shí)舞痰、每個(gè) Region 記憶集中臟卡數(shù)量等各個(gè)可測量步驟花費(fèi)的成本,并分析出平均值诀姚、標(biāo)準(zhǔn)偏差响牛、置信度等統(tǒng)計(jì)信息。統(tǒng)計(jì)狀態(tài)越新越能決定回收的價(jià)值赫段,通過這些信息即可預(yù)測當(dāng)前時(shí)間開始回收呀打,通過哪些 Region 組成回收集可在不超過期望停頓時(shí)間的約束下獲得最高收益。

工作流程

1. 初始標(biāo)記

僅標(biāo)記 GC Roots 能直接關(guān)聯(lián)到的對象并修改 TAMS 指針的值糯笙,讓下一個(gè)階段用戶線程并發(fā)運(yùn)行時(shí)贬丛,能正確地在可用 Region 中分配新對象。速度較快给涕,且是在 Minor GC 發(fā)生時(shí)同步完成豺憔,故實(shí)際上沒有額外的停頓。

2. 并發(fā)標(biāo)記

從 GC Roots 開始遍歷整個(gè)對象圖的過程够庙,耗時(shí)較長但不影響用戶線程運(yùn)行恭应。對象圖掃描完后,還要重新處理 原始快照 記錄下的在并發(fā)時(shí)有引用變動的對象首启。

3. 最終標(biāo)記

對用戶線程做另一個(gè)短暫的暫停暮屡,用于處理并發(fā)階段結(jié)束后仍遺留下來的最后那少量原始快照記錄。

4. 篩選回收

負(fù)責(zé)更新 Region 的統(tǒng)計(jì)數(shù)據(jù)毅桃,對各個(gè) Region 的回收價(jià)值和成本進(jìn)行排序褒纲,根據(jù)用戶所期望的停頓時(shí)間來制定回收計(jì)劃,可自由選擇任意多個(gè) Region 構(gòu)成回收集钥飞,然后把決定回收的那一部分 Region 的存活對象復(fù)制到空的 Region 中莺掠,再清理掉整個(gè)舊 Region 的全部空間。這里的操作涉及存活對象的移動读宙,是必須暫停用戶線程的彻秆,由多條收集器線程并行完成。

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

  • 支持多線程并行收集
  • 停頓時(shí)間低,可動態(tài)設(shè)置預(yù)期值唇兑,且在延遲可控情況下需曾,保證盡可能高的吞吐量
  • Region 內(nèi)存布局使垃圾收集更加動態(tài)化狰闪,按回收收益動態(tài)回收
  • 不會產(chǎn)生內(nèi)存空間碎片
    G1 整體看是基于標(biāo)記 — 整理算法乍惊,但從 Region 局部看撩炊,是基于標(biāo)記 — 復(fù)制算法,兩種算法都無空間碎片留夜。

缺點(diǎn)

  • 內(nèi)存匙铡、CPU 負(fù)載都比 CMS 等其他收集器高

使用場景

  • 大內(nèi)存應(yīng)用
    根據(jù)經(jīng)驗(yàn),通常為堆容量 6GB 到 8GB 之間的應(yīng)用碍粥,小內(nèi)存應(yīng)用中 CMS 收集器表現(xiàn)大概率好過 G1鳖眼,但 G1 仍在不斷更新優(yōu)化中,未來可期嚼摩。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末钦讳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子枕面,更是在濱河造成了極大的恐慌蜂厅,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膊畴,死亡現(xiàn)場離奇詭異,居然都是意外死亡病游,警方通過查閱死者的電腦和手機(jī)唇跨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來衬衬,“玉大人买猖,你說我怎么就攤上這事∽涛荆” “怎么了玉控?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長狮惜。 經(jīng)常有香客問我高诺,道長,這世上最難降的妖魔是什么碾篡? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任虱而,我火速辦了婚禮,結(jié)果婚禮上开泽,老公的妹妹穿的比我還像新娘牡拇。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布惠呼。 她就那樣靜靜地躺著导俘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪剔蹋。 梳的紋絲不亂的頭發(fā)上旅薄,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機(jī)與錄音滩租,去河邊找鬼赋秀。 笑死,一個(gè)胖子當(dāng)著我的面吹牛律想,可吹牛的內(nèi)容都是我干的猎莲。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼技即,長吁一口氣:“原來是場噩夢啊……” “哼著洼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起而叼,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤身笤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后葵陵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體液荸,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年脱篙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了娇钱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,646評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绊困,死狀恐怖文搂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情秤朗,我是刑警寧澤煤蹭,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站取视,受9級特大地震影響硝皂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜作谭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一吧彪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧丢早,春花似錦姨裸、人聲如沸秧倾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽那先。三九已至,卻和暖如春赡艰,著一層夾襖步出監(jiān)牢的瞬間售淡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工慷垮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留揖闸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓料身,卻偏偏與公主長得像汤纸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子芹血,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容