溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JVM快速調(diào)優(yōu)手冊(cè)之二: 常見(jiàn)的垃圾收集器

發(fā)布時(shí)間:2020-07-16 09:09:26 來(lái)源:網(wǎng)絡(luò) 閱讀:433 作者:Stitch_x 欄目:編程語(yǔ)言

如果說(shuō)收集算法是內(nèi)存回收的方法論,那么垃圾收集器就是內(nèi)存回收的具體實(shí)現(xiàn)。

Java虛擬機(jī)規(guī)范中對(duì)垃圾收集器應(yīng)該如何實(shí)現(xiàn)并沒(méi)有任何規(guī)定,
因此不同的廠商、不同版本的虛擬機(jī)所提供的垃圾收集器都可能會(huì)有很大差別,
并且一般都會(huì)提供參數(shù)供用戶根據(jù)自己的應(yīng)用特點(diǎn)和要求組合出各個(gè)年代所使用的收集器。

JVM快速調(diào)優(yōu)手冊(cè)之二: 常見(jiàn)的垃圾收集器

HotSpot虛擬機(jī)的垃圾回收器

圖中展示了7種作用于不同分代的收集器,如果兩個(gè)收集器之間存在連線,就說(shuō)明它們可以搭配使用。虛擬機(jī)所處的區(qū)域,則表示它是屬于新生代收集器還是老年代收集器。

概念理解

  • 并發(fā)和并行

    這兩個(gè)名詞都是并發(fā)編程中的概念,在談?wù)摾占鞯纳舷挛恼Z(yǔ)境中,它們可以解釋如下

    • 并行(Parallel):指多條垃圾收集線程并行工作,但此時(shí)用戶線程仍然處于等待狀態(tài)。
    • 并發(fā)(Concurrent):指用戶線程與垃圾收集線程同時(shí)執(zhí)行(但不一定是并行的,可能會(huì)交替執(zhí)行),用戶程序在繼續(xù)運(yùn)行,而垃圾收集程序運(yùn)行于另一個(gè)CPU上。
  • Minor GC 和 Full GC

    • 新生代GC(Minor GC):指發(fā)生在新生代的垃圾收集動(dòng)作,因?yàn)镴ava對(duì)象大多都具備朝生夕滅的特性,所以Minor GC非常頻繁,一般回收速度也比較快。
    • 老年代GC(Major GC / Full GC):指發(fā)生在老年代的GC,出現(xiàn)了Major GC,經(jīng)常會(huì)伴隨至少一次的Minor GC(但非絕對(duì)的,在Parallel Scavenge收集器的收集策略里就有直接進(jìn)行Major GC的策略選擇過(guò)程)。Major GC的速度一般會(huì)比Minor GC慢10倍以上。
  • 吞吐量

    吞吐量就是CPU用于運(yùn)行用戶代碼的時(shí)間與CPU總消耗時(shí)間的比值,即吞吐量 = 運(yùn)行用戶代碼時(shí)間 /(運(yùn)行用戶代碼時(shí)間 + 垃圾收集時(shí)間)。
    虛擬機(jī)總共運(yùn)行了100分鐘,其中垃圾收集花掉1分鐘,那吞吐量就是99%。

Serial收集器

Serial收集器是最基本、發(fā)展歷史最悠久的收集器,曾經(jīng)(在JDK 1.3.1之前)是虛擬機(jī)新生代收集的唯一選擇。

JVM快速調(diào)優(yōu)手冊(cè)之二: 常見(jiàn)的垃圾收集器

  • 特性

    這個(gè)收集器是一個(gè)單線程的收集器,但它的“單線程”的意義并不僅僅說(shuō)明它只會(huì)使用一個(gè)CPU或一條收集線程去完成垃圾收集工作,更重要的是在它進(jìn)行垃圾收集時(shí),必須暫停其他所有的工作線程,直到它收集結(jié)束。Stop The World

  • 應(yīng)用場(chǎng)景

    Serial收集器是虛擬機(jī)運(yùn)行在Client模式下的默認(rèn)新生代收集器。

  • 優(yōu)勢(shì)

    簡(jiǎn)單而高效(與其他收集器的單線程比),對(duì)于限定單個(gè)CPU的環(huán)境來(lái)說(shuō),Serial收集器由于沒(méi)有線程交互的開(kāi)銷,專心做垃圾收集自然可以獲得最高的單線程收集效率。

ParNew收集器

JVM快速調(diào)優(yōu)手冊(cè)之二: 常見(jiàn)的垃圾收集器

  • 特性

    ParNew收集器其實(shí)就是Serial收集器的多線程版本,除了使用多條線程進(jìn)行垃圾收集之外,其余行為包括Serial收集器可用的所有控制參數(shù)、收集算法、Stop The World、對(duì)象分配規(guī)則、回收策略等都與Serial收集器完全一樣,在實(shí)現(xiàn)上,這兩種收集器也共用了相當(dāng)多的代碼。

  • 應(yīng)用場(chǎng)景

    ParNew收集器是許多運(yùn)行在Server模式下的虛擬機(jī)中首選的新生代收集器。
    很重要的原因是:除了Serial收集器外,目前只有它能與CMS收集器配合工作。
    在JDK 1.5時(shí)期,HotSpot推出了一款在強(qiáng)交互應(yīng)用中幾乎可認(rèn)為有劃時(shí)代意義的垃圾收集器——CMS收集器,這款收集器是HotSpot虛擬機(jī)中第一款真正意義上的并發(fā)收集器,它第一次實(shí)現(xiàn)了讓垃圾收集線程與用戶線程同時(shí)工作。
    不幸的是,CMS作為老年代的收集器,卻無(wú)法與JDK 1.4.0中已經(jīng)存在的新生代收集器Parallel Scavenge配合工作,所以在JDK 1.5中使用CMS來(lái)收集老年代的時(shí)候,新生代只能選擇ParNew或者Serial收集器中的一個(gè)。

  • Serial收集器 VS ParNew收集器

    ParNew收集器在單CPU的環(huán)境中絕對(duì)不會(huì)有比Serial收集器更好的效果,甚至由于存在線程交互的開(kāi)銷,該收集器在通過(guò)超線程技術(shù)實(shí)現(xiàn)的兩個(gè)CPU的環(huán)境中都不能百分之百地保證可以超越Serial收集器。

    然而,隨著可以使用的CPU的數(shù)量的增加,它對(duì)于GC時(shí)系統(tǒng)資源的有效利用還是很有好處的。

Parallel Scavenge收集器

  • 特性

    Parallel Scavenge收集器是一個(gè)新生代收集器,它也是使用復(fù)制算法的收集器,又是并行的多線程收集器。

  • 應(yīng)用場(chǎng)景

    停頓時(shí)間越短就越適合需要與用戶交互的程序,良好的響應(yīng)速度能提升用戶體驗(yàn),而高吞吐量則可以高效率地利用CPU時(shí)間,盡快完成程序的運(yùn)算任務(wù),主要適合在后臺(tái)運(yùn)算而不需要太多交互的任務(wù)。

  • 對(duì)比分析

    • Parallel Scavenge收集器 VS CMS等收集器

    Parallel Scavenge收集器的特點(diǎn)是它的關(guān)注點(diǎn)與其他收集器不同,CMS等收集器的關(guān)注點(diǎn)是盡可能地縮短垃圾收集時(shí)用戶線程的停頓時(shí)間,而Parallel Scavenge收集器的目標(biāo)則是達(dá)到一個(gè)可控制的吞吐量(Throughput)。

    由于與吞吐量關(guān)系密切,Parallel Scavenge收集器也經(jīng)常稱為“吞吐量?jī)?yōu)先”收集器。

    • Parallel Scavenge收集器 VS ParNew收集器

    Parallel Scavenge收集器與ParNew收集器的一個(gè)重要區(qū)別是它具有自適應(yīng)調(diào)節(jié)策略。

    GC自適應(yīng)的調(diào)節(jié)策略

    Parallel Scavenge收集器有一個(gè)參數(shù)-XX:+UseAdaptiveSizePolicy。當(dāng)這個(gè)參數(shù)打開(kāi)之后,就不需要手工指定新生代的大小、Eden與Survivor區(qū)的比例、晉升老年代對(duì)象年齡等細(xì)節(jié)參數(shù)了,虛擬機(jī)會(huì)根據(jù)當(dāng)前系統(tǒng)的運(yùn)行情況收集性能監(jiān)控信息,動(dòng)態(tài)調(diào)整這些參數(shù)以提供最合適的停頓時(shí)間或者最大的吞吐量,這種調(diào)節(jié)方式稱為GC自適應(yīng)的調(diào)節(jié)策略(GC Ergonomics)。

Serial Old收集器

JVM快速調(diào)優(yōu)手冊(cè)之二: 常見(jiàn)的垃圾收集器

  • 特性

    Serial Old是Serial收集器的老年代版本,它同樣是一個(gè)單線程收集器,使用“標(biāo)記-整理”算法。

  • 應(yīng)用場(chǎng)景

    • Client模式

    Serial Old收集器的主要意義也是在于給Client模式下的虛擬機(jī)使用。

    • Server模式

    如果在Server模式下,那么它主要還有兩大用途:一種用途是在JDK 1.5以及之前的版本中與Parallel Scavenge收集器搭配使用,另一種用途就是作為CMS收集器的后備預(yù)案,在并發(fā)收集發(fā)生Concurrent Mode Failure時(shí)使用。

Parallel Old收集器

JVM快速調(diào)優(yōu)手冊(cè)之二: 常見(jiàn)的垃圾收集器

  • 特性

    Parallel Old是Parallel Scavenge收集器的老年代版本,使用多線程“標(biāo)記-整理”算法。

  • 應(yīng)用場(chǎng)景

    在注重吞吐量以及CPU資源敏感的場(chǎng)合,都可以優(yōu)先考慮Parallel Scavenge加Parallel Old收集器。

    這個(gè)收集器是在JDK 1.6中才開(kāi)始提供的,在此之前,新生代的Parallel Scavenge收集器一直處于比較尷尬的狀態(tài)。原因是,如果新生代選擇了Parallel Scavenge收集器,老年代除了Serial Old收集器外別無(wú)選擇(Parallel Scavenge收集器無(wú)法與CMS收集器配合工作)。由于老年代Serial Old收集器在服務(wù)端應(yīng)用性能上的“拖累”,使用了Parallel Scavenge收集器也未必能在整體應(yīng)用上獲得吞吐量最大化的效果,由于單線程的老年代收集中無(wú)法充分利用服務(wù)器多CPU的處理能力,在老年代很大而且硬件比較高級(jí)的環(huán)境中,這種組合的吞吐量甚至還不一定有ParNew加CMS的組合“給力”。直到Parallel Old收集器出現(xiàn)后,“吞吐量?jī)?yōu)先”收集器終于有了比較名副其實(shí)的應(yīng)用組合。

CMS收集器

JVM快速調(diào)優(yōu)手冊(cè)之二: 常見(jiàn)的垃圾收集器

  • 特性

    CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時(shí)間為目標(biāo)的收集器。目前很大一部分的Java應(yīng)用集中在互聯(lián)網(wǎng)站或者B/S系統(tǒng)的服務(wù)端上,這類應(yīng)用尤其重視服務(wù)的響應(yīng)速度,希望系統(tǒng)停頓時(shí)間最短,以給用戶帶來(lái)較好的體驗(yàn)。CMS收集器就非常符合這類應(yīng)用的需求。

    CMS收集器是基于“標(biāo)記—清除”算法實(shí)現(xiàn)的,它的運(yùn)作過(guò)程相對(duì)于前面幾種收集器來(lái)說(shuō)更復(fù)雜一些,整個(gè)過(guò)程分為4個(gè)步驟:

    1. 初始標(biāo)記(CMS initial mark)

      初始標(biāo)記僅僅只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象,速度很快,需要“Stop The World”。

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

      并發(fā)標(biāo)記階段就是進(jìn)行GC Roots Tracing的過(guò)程。

    3. 重新標(biāo)記(CMS remark)

      重新標(biāo)記階段是為了修正并發(fā)標(biāo)記期間因用戶程序繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記錄,這個(gè)階段的停頓時(shí)間一般會(huì)比初始標(biāo)記階段稍長(zhǎng)一些,但遠(yuǎn)比并發(fā)標(biāo)記的時(shí)間短,仍然需要“Stop The World”。

    4. 并發(fā)清除(CMS concurrent sweep)

      并發(fā)清除階段會(huì)清除對(duì)象。

      由于整個(gè)過(guò)程中耗時(shí)最長(zhǎng)的并發(fā)標(biāo)記和并發(fā)清除過(guò)程收集器線程都可以與用戶線程一起工作,所以,從總體上來(lái)說(shuō),CMS收集器的內(nèi)存回收過(guò)程是與用戶線程一起并發(fā)執(zhí)行的。

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

    CMS是一款優(yōu)秀的收集器,它的主要優(yōu)點(diǎn)在名字上已經(jīng)體現(xiàn)出來(lái)了:并發(fā)收集、低停頓。

  • 缺點(diǎn)

    • CMS收集器對(duì)CPU資源非常敏感

    其實(shí),面向并發(fā)設(shè)計(jì)的程序都對(duì)CPU資源比較敏感。在并發(fā)階段,它雖然不會(huì)導(dǎo)致用戶線程停頓,但是會(huì)因?yàn)檎加昧艘徊糠志€程(或者說(shuō)CPU資源)而導(dǎo)致應(yīng)用程序變慢,總吞吐量會(huì)降低。

    CMS默認(rèn)啟動(dòng)的回收線程數(shù)是(CPU數(shù)量+3)/ 4,也就是當(dāng)CPU在4個(gè)以上時(shí),并發(fā)回收時(shí)垃圾收集線程不少于25%的CPU資源,并且隨著CPU數(shù)量的增加而下降。但是當(dāng)CPU不足4個(gè)(譬如2個(gè))時(shí),CMS對(duì)用戶程序的影響就可能變得很大。

    • CMS收集器無(wú)法處理浮動(dòng)垃圾

    CMS收集器無(wú)法處理浮動(dòng)垃圾,可能出現(xiàn)“Concurrent Mode Failure”失敗而導(dǎo)致另一次Full GC的產(chǎn)生。

    由于CMS并發(fā)清理階段用戶線程還在運(yùn)行著,伴隨程序運(yùn)行自然就還會(huì)有新的垃圾不斷產(chǎn)生,這一部分垃圾出現(xiàn)在標(biāo)記過(guò)程之后,CMS無(wú)法在當(dāng)次收集中處理掉它們,只好留待下一次GC時(shí)再清理掉。這一部分垃圾就稱為“浮動(dòng)垃圾”。
    也是由于在垃圾收集階段用戶線程還需要運(yùn)行,那也就還需要預(yù)留有足夠的內(nèi)存空間給用戶線程使用,因此CMS收集器不能像其他收集器那樣等到老年代幾乎完全被填滿了再進(jìn)行收集,需要預(yù)留一部分空間提供并發(fā)收集時(shí)的程序運(yùn)作使用。要是CMS運(yùn)行期間預(yù)留的內(nèi)存無(wú)法滿足程序需要,就會(huì)出現(xiàn)一次“Concurrent Mode Failure”失敗,這時(shí)虛擬機(jī)將啟動(dòng)后備預(yù)案:臨時(shí)啟用Serial Old收集器來(lái)重新進(jìn)行老年代的垃圾收集,這樣停頓時(shí)間就很長(zhǎng)了。

    • CMS收集器會(huì)產(chǎn)生大量空間碎片

    CMS是一款基于“標(biāo)記—清除”算法實(shí)現(xiàn)的收集器,這意味著收集結(jié)束時(shí)會(huì)有大量空間碎片產(chǎn)生。

    空間碎片過(guò)多時(shí),將會(huì)給大對(duì)象分配帶來(lái)很×××煩,往往會(huì)出現(xiàn)老年代還有很大空間剩余,但是無(wú)法找到足夠大的連續(xù)空間來(lái)分配當(dāng)前對(duì)象,不得不提前觸發(fā)一次Full GC。

G1收集器

JVM快速調(diào)優(yōu)手冊(cè)之二: 常見(jiàn)的垃圾收集器

  • 特性

    G1(Garbage-First)是一款面向服務(wù)端應(yīng)用的垃圾收集器。HotSpot開(kāi)發(fā)團(tuán)隊(duì)賦予它的使命是未來(lái)可以替換掉JDK 1.5中發(fā)布的CMS收集器。與其他GC收集器相比,G1具備如下特點(diǎn)。

    在G1之前的其他收集器進(jìn)行收集的范圍都是整個(gè)新生代或者老年代,而G1不再是這樣。使用G1收集器時(shí),Java堆的內(nèi)存布局就與其他收集器有很大差別,它將整個(gè)Java堆劃分為多個(gè)大小相等的獨(dú)立區(qū)域(Region),雖然還保留有新生代和老年代的概念,但新生代和老年代不再是物理隔離的了,它們都是一部分Region(不需要連續(xù))的集合。

    G1收集器之所以能建立可預(yù)測(cè)的停頓時(shí)間模型,是因?yàn)樗梢杂杏?jì)劃地避免在整個(gè)Java堆中進(jìn)行全區(qū)域的垃圾收集。G1跟蹤各個(gè)Region里面的垃圾堆積的價(jià)值大?。ɑ厥账@得的空間大小以及回收所需時(shí)間的經(jīng)驗(yàn)值),在后臺(tái)維護(hù)一個(gè)優(yōu)先列表,每次根據(jù)允許的收集時(shí)間,優(yōu)先回收價(jià)值最大的Region(這也就是Garbage-First名稱的來(lái)由)。這種使用Region劃分內(nèi)存空間以及有優(yōu)先級(jí)的區(qū)域回收方式,保證了G1收集器在有限的時(shí)間內(nèi)可以獲取盡可能高的收集效率。

    • 并行與并發(fā)

    G1能充分利用多CPU、多核環(huán)境下的硬件優(yōu)勢(shì),使用多個(gè)CPU來(lái)縮短Stop-The-World停頓的時(shí)間,部分其他收集器原本需要停頓Java線程執(zhí)行的GC動(dòng)作,G1收集器仍然可以通過(guò)并發(fā)的方式讓Java程序繼續(xù)執(zhí)行。

    • 分代收集

    與其他收集器一樣,分代概念在G1中依然得以保留。雖然G1可以不需要其他收集器配合就能獨(dú)立管理整個(gè)GC堆,但它能夠采用不同的方式去處理新創(chuàng)建的對(duì)象和已經(jīng)存活了一段時(shí)間、熬過(guò)多次GC的舊對(duì)象以獲取更好的收集效果。

    • 空間整合

    與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。

    • 可預(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毫秒。

  • 執(zhí)行過(guò)程

    G1收集器的運(yùn)作大致可劃分為以下幾個(gè)步驟:

    • 初始標(biāo)記(Initial Marking)

    初始標(biāo)記階段僅僅只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象,并且修改TAMS(Next Top at Mark Start)的值,讓下一階段用戶程序并發(fā)運(yùn)行時(shí),能在正確可用的Region中創(chuàng)建新對(duì)象,這階段需要停頓線程,但耗時(shí)很短。

    • 并發(fā)標(biāo)記(Concurrent Marking)

    并發(fā)標(biāo)記階段是從GC Root開(kāi)始對(duì)堆中對(duì)象進(jìn)行可達(dá)性分析,找出存活的對(duì)象,這階段耗時(shí)較長(zhǎng),但可與用戶程序并發(fā)執(zhí)行。

    • 最終標(biāo)記(Final Marking)

    最終標(biāo)記階段是為了修正在并發(fā)標(biāo)記期間因用戶程序繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分標(biāo)記記錄,虛擬機(jī)將這段時(shí)間對(duì)象變化記錄在線程Remembered Set Logs里面,最終標(biāo)記階段需要把Remembered Set Logs的數(shù)據(jù)合并到Remembered Set中,這階段需要停頓線程,但是可并行執(zhí)行。

    • 篩選回收(Live Data Counting and Evacuation)

    篩選回收階段首先對(duì)各個(gè)Region的回收價(jià)值和成本進(jìn)行排序,根據(jù)用戶所期望的GC停頓時(shí)間來(lái)制定回收計(jì)劃,這個(gè)階段其實(shí)也可以做到與用戶程序一起并發(fā)執(zhí)行,但是因?yàn)橹换厥找徊糠諶egion,時(shí)間是用戶可控制的,而且停頓用戶線程將大幅提高收集效率。

總結(jié)

雖然我們是在對(duì)各個(gè)收集器進(jìn)行比較,但并非為了挑選出一個(gè)最好的收集器。因?yàn)橹钡浆F(xiàn)在為止還沒(méi)有最好的收集器出現(xiàn),更加沒(méi)有萬(wàn)能的收集器,所以我們選擇的只是對(duì)具體應(yīng)用最合適的收集器。這點(diǎn)不需要多加解釋就能證明:如果有一種放之四海皆準(zhǔn)、任何場(chǎng)景下都適用的完美收集器存在,那HotSpot虛擬機(jī)就沒(méi)必要實(shí)現(xiàn)那么多不同的收集器了。
JVM快速調(diào)優(yōu)手冊(cè)之二: 常見(jiàn)的垃圾收集器

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI