面試官:怎么做JDK8的垃圾收集器的調(diào)優(yōu)(面試常問)

看著面試官真誠(chéng)的眼神,心中暗想看起來(lái)年紀(jì)輕輕卻提出如此直擊靈魂的問題。擦了擦額頭上汗,我稍微調(diào)整了一下緊張的情緒,對(duì)面試官說(shuō):
在JDK8中有Serial收集器、Parallel收集器、CMS收集器、G1收集器這么幾種收集器,需要根據(jù)實(shí)際硬件配置和業(yè)務(wù)需求進(jìn)行選擇調(diào)優(yōu)。
如此淺顯的回答,無(wú)法讓面試官達(dá)到深入的要求,肯定不能滿足面試官?gòu)?qiáng)烈的需求,果不其然面試官又追問到:如果是桌面應(yīng)用,內(nèi)存占用也就100MB,應(yīng)該選擇哪種垃圾收集器呢?我快速的回答:Serial收集器。看著面試官期待的眼神,我又詳細(xì)解釋到:
Serial收集器
Serial收集器是使用單線程處理所有的垃圾收集工作的,因?yàn)闆]有多線程的額外開銷,相對(duì)來(lái)說(shuō)也是比較有效的。所以,最適合單核CPU環(huán)境,因?yàn)楸緛?lái)也沒辦法利用多核。不過,當(dāng)應(yīng)用的使用的內(nèi)存大小在100MB左右甚至更小的時(shí)候,在也適用于多核CPU的環(huán)境。
我一邊說(shuō)著,一邊在紙上畫了起來(lái):

Client模式的JVM默認(rèn)的垃圾收集器就是Serial收集器,或者可以使用JVM參數(shù)-XX:+UseSerialGC顯式啟用Serial收集器。
面試官又追問到:如果是要求高吞吐量的應(yīng)用,使用較大內(nèi)存并且有多核CPU,應(yīng)該選擇哪種垃圾收集器呢?我快速的回答:Parallel收集器??粗嬖嚬倨诖难凵?,我又詳細(xì)解釋到:
Parallel收集器
Parallel收集器是類似于Serial收集器的分代收集器,主要區(qū)別是在垃圾回收的時(shí)候使用了多個(gè)線程進(jìn)行加速垃圾的收集。所以,對(duì)于使用較大內(nèi)存并且有多核CPU的環(huán)境更加適合。
我一邊說(shuō)著,一邊在紙上畫了起來(lái):

Server模式的JVM默認(rèn)的垃圾收集器就是Parallel收集器,也可以使用JVM參數(shù)-XX:+UseParallelGC啟用。啟用Parallel收集器后默認(rèn)情況下,Minor垃圾收集(針對(duì)年輕代的垃圾收集)和Major垃圾收集(針對(duì)老年代的垃圾收集)都是并行執(zhí)行的,可以進(jìn)一步減少垃圾收集的開銷。
Parallel收集器可以通過JVM參數(shù)指定最大垃圾收集暫停時(shí)間、吞吐量(用戶代碼運(yùn)行時(shí)間/(用戶代碼運(yùn)行時(shí)間+垃圾收集運(yùn)行時(shí)間))和堆占用空間的目標(biāo)值:
- -XX:MaxGCPauseMillis:最大垃圾收集暫停時(shí)間,單位為毫秒,如:-XX:MaxGCPauseMillis=200,表示垃圾收集暫停時(shí)間最大為200毫秒。默認(rèn)情況下,沒有指定最大垃圾收集暫停時(shí)間。如果指定了暫停時(shí)間目標(biāo),則會(huì)調(diào)整堆大小與垃圾收集相關(guān)的其他參數(shù),使垃圾收集的暫停時(shí)間短于指定值。這些調(diào)整可能導(dǎo)致降低應(yīng)用的整體吞吐量,也有可能無(wú)法始終滿足所指定的最大垃圾收集暫停時(shí)間目標(biāo)。
- -XX:GCTimeRatio:吞吐量大小,如:-XX:GCTimeRatio=19,表示將垃圾收集運(yùn)行時(shí)間的目標(biāo)設(shè)定為應(yīng)用總運(yùn)行時(shí)間(用戶代碼運(yùn)行時(shí)間+垃圾收集運(yùn)行時(shí)間)的1/(1+19),即5%。默認(rèn)值為99,垃圾收集的目標(biāo)時(shí)間占應(yīng)用總運(yùn)行時(shí)間的1/(1+99),即1%。
- -Xmx:堆占用的最大占用空間,如:-Xmx1G,表示堆占用的最大占用空間為1GB。另外,Parallel收集器還有一個(gè)隱含的目標(biāo):只要滿足其他目標(biāo)的同時(shí),把堆占用內(nèi)存的大小最小化。
這三個(gè)目標(biāo)是有優(yōu)先級(jí)的:
- 高優(yōu)先級(jí):最大垃圾收集暫停時(shí)間
- 中優(yōu)先級(jí):吞吐量目標(biāo)
- 低優(yōu)先級(jí):最小堆占用內(nèi)存目標(biāo)
Parallel收集器按照指定的目標(biāo)對(duì)分代大小和底層進(jìn)行自動(dòng)調(diào)節(jié),盡量達(dá)到指定的目標(biāo),但不保證百分之百能達(dá)到。
面試官又追問到:如果同樣是使用較大內(nèi)存并且有多核CPU,但是要求垃圾收集暫停時(shí)間要盡可能短的Web應(yīng)用,應(yīng)該選擇哪種垃圾收集器呢?我稍微思考了一下,回答:CMS收集器??粗嬖嚬倨诖难凵?,我又詳細(xì)解釋到:
CMS收集器
CMS(Concurrent Mark Sweep)收集器是為那些要求垃圾收集暫停時(shí)間盡可能短,并且可以和垃圾收集器共享CPU資源的應(yīng)用設(shè)計(jì)的。具有相對(duì)較大的內(nèi)存使用并有多核CPU的應(yīng)用,往往會(huì)更適合CMS收集器的使用??梢允褂肑VM參數(shù)-XX:+UseConcMarkSweepGC啟用CMS收集器,啟用后同時(shí)作用于Minor垃圾收集(針對(duì)年輕代的垃圾收集)和Major垃圾收集(針對(duì)老年代的垃圾收集)。
CMS收集器嘗試通過使用單獨(dú)的垃圾收集器線程在執(zhí)行用戶線程的同時(shí)并跟蹤可訪問對(duì)象,來(lái)減少由于Major垃圾收集而導(dǎo)致的暫停時(shí)間。在每個(gè)Major垃圾收集周期中,CMS收集器會(huì)在收集開始時(shí)暫停所有用戶線程一小段時(shí)間,然后在收集的中期再次暫停。第二個(gè)暫停往往是兩個(gè)暫停中較長(zhǎng)的一個(gè),在兩個(gè)暫停之間都使用多個(gè)線程并行做收集工作的。所以,CMS收集器的垃圾收集過程分為以下四個(gè)步驟:
- 初始標(biāo)記(CMS initial mark):這個(gè)步驟會(huì)暫停所有用戶線程,但耗時(shí)非常短,標(biāo)記GC Root直接關(guān)聯(lián)的對(duì)象。
- 并發(fā)標(biāo)記(CMS concurrent mark):這個(gè)步驟耗時(shí)較長(zhǎng),但用戶線程可同時(shí)運(yùn)行,標(biāo)記至GC Root有可達(dá)路徑的對(duì)象。
- 重新標(biāo)記(CMS remark):這個(gè)步驟會(huì)暫停所有用戶線程,但耗時(shí)比較短。由于步驟2用戶線程同步運(yùn)行,所以要修正在步驟二中用戶線程同步運(yùn)行產(chǎn)生對(duì)象標(biāo)記的變動(dòng)。
- 并發(fā)清除(CMS concurrent sweep):這個(gè)步驟耗時(shí)較長(zhǎng),但用戶線程可同時(shí)運(yùn)行。
我一邊說(shuō)著,一邊在紙上畫了起來(lái):

面試官繼續(xù)追問到:如果堆中有超過50%的活躍對(duì)象,分配對(duì)象和對(duì)象升代的頻率較高,垃圾收集停頓時(shí)間大于0.5秒,應(yīng)該選擇哪種垃圾收集器呢?我稍微思考了一下,回答:G1收集器??粗嬖嚬倨诖难凵?,我又詳細(xì)解釋到:
G1收集器
G1(Garbage-First)收集器是一款主要面向服務(wù)端應(yīng)用的垃圾收集器,適用于具有大內(nèi)存的多核CPU的服務(wù)器。它嘗試在高概率下同時(shí)滿足較小的垃圾收集暫停時(shí)間和較高的吞吐量。所有堆相關(guān)的操作(如:全局標(biāo)記)與用戶線程同時(shí)運(yùn)行,這樣可以避免隨著堆內(nèi)存的大小的增加垃圾收集的停頓時(shí)間也跟著增加。
G1收集器是垃圾收集技術(shù)歷史上里程碑的成果,它跳出了之前收集整個(gè)代垃圾的思維模式,開創(chuàng)了收集器面向局部收集的設(shè)計(jì)思路和基于Rigion的內(nèi)存布局形式。在之后的JDK版本中,G1收集器正在逐漸成為了CMS收集器的替代者和繼任者。
G1收集器雖然遵循分代收集的設(shè)計(jì),但是整個(gè)堆的內(nèi)存設(shè)計(jì)有顯著的不同。整個(gè)堆被劃分為一組大小相等的獨(dú)立區(qū)域(Region),每個(gè)獨(dú)立區(qū)域(Region)都有一個(gè)連續(xù)的虛擬內(nèi)存范圍,并且根據(jù)需要在邏輯被劃分為年輕代的Eden區(qū)、Survivor區(qū)或者老年代。
我一邊說(shuō)著,一邊在紙上畫了起來(lái):

通過JVM參數(shù)-XX:MaxGCPauseMillis來(lái)給G1收集器指定垃圾收集的目標(biāo)停頓時(shí)間,默認(rèn)是200毫秒。G1收集器會(huì)使用預(yù)測(cè)模型來(lái)估算停頓時(shí)間內(nèi)可以收集多少個(gè)獨(dú)立區(qū)域。在一次垃圾回收結(jié)束時(shí),G1收集器會(huì)選擇下次將要收集哪些獨(dú)立區(qū)域。通常情況下,G1收集器通過選擇年輕代獨(dú)立區(qū)域的數(shù)量來(lái)控制垃圾收集的停頓時(shí)間。與其他垃圾收集器一樣,可以通過參數(shù)指定年輕代的大小,但是這樣做可能會(huì)影響G1收集器達(dá)到停頓時(shí)間目標(biāo)的效果。除了停頓時(shí)間目標(biāo)之外,還可以通過JVM參數(shù)-XX:GCPauseIntervalMillis指定停頓的間隔時(shí)長(zhǎng),默認(rèn)是0。
聽了我的回答后,面試官對(duì)我會(huì)心一笑,我仿佛還在她的眼神中看到了一絲傾慕。正所謂:金風(fēng)玉露一相逢,便勝卻人間無(wú)數(shù),欲知后事如何,且聽下回分解。
總結(jié)
到此這篇關(guān)于面試官:怎么做JDK8的垃圾收集器的調(diào)優(yōu)(面試常問)的文章就介紹到這了,更多相關(guān)JDK8的垃圾收集器的調(diào)優(yōu)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用.NET Core3.0創(chuàng)建一個(gè)Windows服務(wù)的方法
這篇文章主要介紹了使用.NET Core3.0創(chuàng)建一個(gè)Windows服務(wù)的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2019-04-04
gradle項(xiàng)目中資源文件的相對(duì)路徑打包技巧必看
這篇文章主要介紹了gradle項(xiàng)目中資源文件的相對(duì)路徑打包技巧必看篇,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2020-11-11
AbstractQueuedSynchronizer內(nèi)部類Node使用講解
這篇文章主要為大家介紹了AbstractQueuedSynchronizer內(nèi)部類Node使用講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
java 反射 動(dòng)態(tài)調(diào)用不同類的靜態(tài)方法(推薦)
下面小編就為大家?guī)?lái)一篇JAVA 反射 動(dòng)態(tài)調(diào)用不同類的靜態(tài)方法(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2016-08-08
SpringBoot中controller深層詳細(xì)講解
這篇文章主要介紹了SpringBoot在Controller層接收參數(shù)的常用方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-02-02
mybatis通過TypeHandler?list轉(zhuǎn)換string類型轉(zhuǎn)換方式
這篇文章主要介紹了mybatis通過TypeHandler?list轉(zhuǎn)換string類型轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
使用Java編寫導(dǎo)出不確定行數(shù)列數(shù)數(shù)據(jù)的工具類
這篇文章主要為大家詳細(xì)介紹了如何使用Java編寫導(dǎo)出不確定行數(shù)列數(shù)數(shù)據(jù)的工具類,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03

