說(shuō)到如何進(jìn)行Jvm虛擬機(jī)優(yōu)化划鸽,第一時(shí)間想到應(yīng)該都是配置堆內(nèi)存的大小,其次就是Java垃圾收集器了。Java垃圾收集器的配置對(duì)于Jvm優(yōu)化來(lái)說(shuō)是一個(gè)很重要的選擇我衬,選擇合適的垃圾收集器可以讓Jvm的性能有一個(gè)很大的提升曹动。截止Jdk 1.8斋日,一共有7款不同的垃圾收集器。每一款不同的垃圾收集器都有不同的特點(diǎn)墓陈,在具體使用的時(shí)候恶守,需要根據(jù)具體的情況選用不同的垃圾收集器。這幾款垃圾收集器之間有如下聯(lián)系:
下面一一介紹這些垃圾回收器的特點(diǎn)。
Serial收集器
Serial收集器是一個(gè)基本的,古老的新生代垃圾收集器骂维。這個(gè)垃圾收集器是一個(gè)單線(xiàn)程的收集器廓推,在它進(jìn)行垃圾回收的時(shí)候,其他的工作線(xiàn)程都會(huì)被暫停,直到它收集結(jié)束。這也就是說(shuō),如果Jvm參數(shù)配置有問(wèn)題或者內(nèi)存不夠科侈,導(dǎo)致頻繁的gc,可能每隔一段時(shí)間應(yīng)用就會(huì)暫停響應(yīng)炒事。如果暫停的時(shí)間太長(zhǎng)臀栈,用戶(hù)就無(wú)法接受了,而且這個(gè)過(guò)程是不可控制的挠乳,是虛擬機(jī)在后臺(tái)自動(dòng)發(fā)起和自動(dòng)完成的挂脑。整個(gè)運(yùn)行過(guò)程如下所示:
盡管Serial收集器有如此多的缺點(diǎn),但是從JDK1.3開(kāi)始到JDK1.7都一直是默認(rèn)的運(yùn)行在Client模式下的新生代收集器欲侮。原因在于Serial收集器是一個(gè)簡(jiǎn)單高效的收集器崭闲,沒(méi)有線(xiàn)程切換的開(kāi)銷(xiāo)等等,在一般的Client應(yīng)用中需要回收的內(nèi)存也不是很大威蕉,垃圾回收停頓的時(shí)間不是很長(zhǎng)刁俭,是可以接受的。所以韧涨,Serial收集器對(duì)于運(yùn)行在Client模式下的虛擬機(jī)來(lái)說(shuō)是一個(gè)很好的選擇牍戚。
ParNew收集器
ParNew收集器是Serial收集器的多線(xiàn)程版本,除了使用多線(xiàn)程進(jìn)行垃圾收集之外虑粥,其余行為包括Serial收集器可用的所有控制參數(shù)如孝、收集算法、Stop The World娩贷、對(duì)象分配規(guī)則第晰、回收策略等都與Serial收集器完全一樣,它的工作過(guò)程如下:
ParNew收集器除了多線(xiàn)程收集之外,其他與Serial收集器相比并沒(méi)有太多創(chuàng)新之處茁瘦,但他卻是許多運(yùn)行在Server模式下的虛擬機(jī)中首選的新生代收集器品抽,其中有一個(gè)與性能無(wú)關(guān)但很重要的原因是,除了Serial收集器外甜熔,目前只有它能與CMS收集器配合工作圆恤。
雖然ParNew收集器是多線(xiàn)程收集,但是它的性能并不一定比Serial收集器好腔稀。因?yàn)榫€(xiàn)程切換等開(kāi)銷(xiāo)的因素盆昙,在單CPU環(huán)境中它的性能是不如Serial收集器的,就算有2個(gè)CPU也不一定能說(shuō)絕對(duì)比Serial好焊虏。但是隨著CPU核數(shù)的增多弱左,其最終效果肯定是優(yōu)于Serial收集器的。
ParNew收集器默認(rèn)會(huì)開(kāi)啟與CPU相同數(shù)量的線(xiàn)程來(lái)進(jìn)行垃圾收集炕淮,可以通過(guò)-XX:ParallelGCThreads參數(shù)來(lái)限制垃圾收集的線(xiàn)程數(shù)。
Parallel Scavenge收集器
Parallel Scavenge收集器是一個(gè)新生代收集器跳夭,它也是使用復(fù)制算法的收集器涂圆,也是并行的多線(xiàn)程收集器”姨荆看上去與ParNew收集器類(lèi)似润歉,實(shí)際上它們的關(guān)注點(diǎn)并不一樣。
ParNew收集器主要關(guān)注的是回收內(nèi)存的速度颈抚,盡可能地縮短垃圾收集時(shí)用戶(hù)線(xiàn)程的停頓時(shí)間踩衩,而Parallel Scavenge收集器的目標(biāo)則是達(dá)到一個(gè)可控制的吞吐量。
停頓時(shí)間越短越適合需要與用戶(hù)交互的程序贩汉,而高吞吐量可以高效率地利用CPU時(shí)間驱富,盡快完成程序的任務(wù),主要適合在后臺(tái)運(yùn)輸而不需要太多交互的任務(wù)匹舞。
Parallel Scavenge收集器提供了兩個(gè)參數(shù)用于精確控制吞吐量褐鸥,分別是控制最大垃圾收集停頓時(shí)間的-XX:MaxGCPauseMillis參數(shù)以及直接設(shè)置吞吐量大小的-XX:GCTimeRatio參數(shù)。如果對(duì)Parallel Scavenge收集器不太熟悉赐稽,可以設(shè)置-XX:+UseAdaptiveSizePolicy叫榕,這個(gè)參數(shù)是一個(gè)開(kāi)關(guān)。打開(kāi)之后不需要手工指定新生代的大墟⒍妗(-Xmn)晰绎、Eden與Survivor區(qū)的比例(-XX:SuvivorRatio)、晉升老年代對(duì)象大欣ǘ (-XX:PretenureSizeThreshold)等細(xì)節(jié)參數(shù)了荞下,虛擬機(jī)會(huì)根據(jù)當(dāng)前系統(tǒng)的運(yùn)行情況收集性能監(jiān)控信息,動(dòng)態(tài)調(diào)整這些參數(shù)以提供最合適的停頓時(shí)間或者最大的吞吐量。
Parallel Scavenge收集器的工作過(guò)程如圖所示:
Serial Old收集器
Serial Old是Serial收集器的老年代版本锄弱,它同樣是一個(gè)單線(xiàn)程收集器考蕾,使用“標(biāo)記-整理”算法。這個(gè)收集器的主要意義也是在于給Client模式下的虛擬機(jī)使用会宪。如果在Server模式下肖卧,那么它主要還有兩個(gè)用途:一種用途是在JDK1.5以及之前的版本中與Parallel Scavenge收集器搭配使用,另一種用途就是作為CMS收集器的后備預(yù)案掸鹅,在并發(fā)收集發(fā)生Concurrent Mode Failure時(shí)使用塞帐。Serial Old收集器的工作過(guò)程如圖所示:
Parallel Old收集器
Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多線(xiàn)程和“標(biāo)記-整理”算法巍沙。這個(gè)收集器是在JDK1.6中才開(kāi)始提供的葵姥,在此之前,新生代的Parallel Scavenge收集器一直處于比較尷尬的狀態(tài)句携。原因是榔幸,如果新生代選擇Parallel Scavenge收集器,老年代除了Serial Old收集器外別無(wú)選擇矮嫉。直到Parallel Old收集器出現(xiàn)后削咆,“吞吐量?jī)?yōu)先”收集器終于有了比較名副其實(shí)的應(yīng)用組合,在注重吞吐量以及CPU資源敏感的場(chǎng)合蠢笋,都可以?xún)?yōu)先考慮Parallel Scavenge加Parallel Old收集器拨齐。Parallel Old收集器的工作過(guò)程如圖所示:
CMS收集器
CMS收集器是一種以獲取最短回收停頓時(shí)間為目標(biāo)的收集器。是基于“標(biāo)記-清除”算法實(shí)現(xiàn)的昨寞,它的運(yùn)作過(guò)程相對(duì)于前面幾種收集器來(lái)說(shuō)更復(fù)雜一些瞻惋,分為4個(gè)步驟:
- 初始標(biāo)記
- 并發(fā)標(biāo)記
- 重新標(biāo)記
- 并發(fā)清除
其中初始標(biāo)記和重新標(biāo)記這兩個(gè)步驟仍然需要“Stop the world”。初始標(biāo)記僅僅只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象援岩,速度很快歼狼,并發(fā)標(biāo)記階段就是GC Roots Tracing的過(guò)程,而重新標(biāo)記階段則是為了修正并發(fā)標(biāo)記期間因用戶(hù)程序繼續(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í)間短。
由于整個(gè)過(guò)程中耗時(shí)最長(zhǎng)的并發(fā)標(biāo)記和并發(fā)清除過(guò)程收集器線(xiàn)程都可以與用戶(hù)線(xiàn)程一起工作凹蜈,所以限寞,從總體上來(lái)說(shuō),CMS收集器的內(nèi)存回收過(guò)程是用戶(hù)線(xiàn)程一起并發(fā)執(zhí)行的仰坦。CMS收集器的工作過(guò)程如圖所示:
CMS是一款優(yōu)秀的收集器履植,它的優(yōu)點(diǎn)有:并發(fā)收集、低停頓悄晃,但它有以下3個(gè)明顯的缺點(diǎn):
- CMS收集器對(duì)CPU資源非常敏感玫霎。在并發(fā)階段凿滤,它雖然不會(huì)導(dǎo)致用戶(hù)停頓,但是會(huì)因?yàn)檎加昧艘徊糠志€(xiàn)程而導(dǎo)致應(yīng)用程序變慢庶近,總吞吐量會(huì)降低翁脆。
- CMS收集器無(wú)法處理浮動(dòng)垃圾,可能出現(xiàn)“Concurrent Mode Failure”失敗而導(dǎo)致另一次Full GC的產(chǎn)生鼻种。由于CMS并發(fā)清理階段用戶(hù)線(xiàn)程還在運(yùn)行著反番,伴隨著程序運(yùn)行自然就還會(huì)有新的垃圾不斷產(chǎn)生,這部分垃圾出現(xiàn)在標(biāo)記過(guò)程之后叉钥,CMS無(wú)法在檔次收集中處理掉它們罢缸,只好留待下一次GC時(shí)再清理掉。這一部分垃圾就稱(chēng)為“浮動(dòng)垃圾”投队。
- 最后一個(gè)缺點(diǎn)是枫疆,CMS是基于“標(biāo)記-清除”算法實(shí)現(xiàn)的收集器,容易產(chǎn)生大量的空間碎片敷鸦,導(dǎo)致沒(méi)有足夠大的連續(xù)空間來(lái)分配當(dāng)前對(duì)象息楔,不得不提前觸發(fā)一次Full GC。
G1 收集器
G1收集器是當(dāng)今收集器技術(shù)發(fā)展的最前沿成果之一扒披,是一款面向服務(wù)端應(yīng)用的垃圾收集器值依,它有如下特點(diǎn):
- 并行與并發(fā):G1能充分利用多CPU,多核環(huán)境下的硬件優(yōu)勢(shì)谎碍,使用多個(gè)CPU來(lái)縮短Stop-The-World停頓的時(shí)間,部分其他收集器原來(lái)需要停頓Java線(xiàn)程執(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)的收集器,從局部上來(lái)看是基于“復(fù)制”算法實(shí)現(xiàn)的甸鸟,但無(wú)論如何惦费,這兩種算法都意味著G1運(yùn)作期間不會(huì)產(chǎn)生內(nèi)存空間碎片,收集后能提供規(guī)整的可用內(nèi)存抢韭。
- 可預(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毫秒。
G1收集器的運(yùn)作大致可劃分為以下幾個(gè)步驟:
- 初始標(biāo)記
- 并發(fā)標(biāo)記
- 最終標(biāo)記
- 篩選標(biāo)記
初始標(biāo)記階段僅僅只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象鞍匾,并且修改TAMS(Next Top at Mart Start)的值交洗,讓下一階段用戶(hù)程序并發(fā)運(yùn)行時(shí),能在正確可用的Region中創(chuàng)建新對(duì)象橡淑,這階段需要停頓線(xiàn)程构拳,但耗時(shí)很短。
并發(fā)標(biāo)記階段是從GC Root開(kāi)始對(duì)堆中對(duì)象進(jìn)行可達(dá)性分析梳码,找出存活的對(duì)象隐圾,這階段耗時(shí)較長(zhǎng),但可與用戶(hù)程序并發(fā)執(zhí)行掰茶。
最終標(biāo)記階段則是為了修正在并發(fā)標(biāo)記期間因用戶(hù)程序繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分暇藏,這個(gè)階段需要停頓線(xiàn)程,但是可并行執(zhí)行濒蒋。
在篩選回收階段首先對(duì)各個(gè)Region的回收價(jià)值和成本進(jìn)行排序盐碱,根據(jù)用戶(hù)所期望的GC停頓時(shí)間來(lái)制定回收計(jì)劃。
G1收集器的工作過(guò)程如圖所示: