经典面试题 | 讲一下垃圾回收器都有哪些?
垃圾回收器有哪些?是一個(gè)高頻的面試題,那本文就詳細(xì)來解答這個(gè)問題。
因?yàn)椴煌膹S商(IBM、Oracle),實(shí)現(xiàn)的垃圾回收器各不相同,而本文要討論的是 Oracle 的 HotSpot 虛擬機(jī)所使用的垃圾回收器。
常用垃圾回收器,如下圖所示:
新生代回收器:Serial、ParNew、Parallel Scavenge
老年代回收器:Serial Old、Parallel Old、CMS
整堆回收器:G1
其中相互連線的垃圾回收器,表示可以相互搭配使用。
新生代 And 老生代
目前常用的商用垃圾收集器都使用的是分代垃圾回收方式。
分代垃圾回收器把內(nèi)存分為:新生代(Young Generation)和老生代(Tenured Generation),如下圖所示:
(圖片來自fancydeepin)
默認(rèn)情況下,新生代和老生代的內(nèi)存比例是 1:2,該值可以通過 -XX:NewRatio 來設(shè)定。
新生代(Young Generation)
程序中的大部分對(duì)象都符合“朝生夕死”的特性,所以絕大數(shù)新創(chuàng)建的對(duì)象都會(huì)存放在新生代,除非是大對(duì)象會(huì)直接進(jìn)入老生代。新生代采用的是復(fù)制算法,這樣可以更高效的回收內(nèi)存空間。
新生代有細(xì)分為:Eden、Form Survivor、To Survivor 三個(gè)區(qū)域,默認(rèn)的比例是 8:1:1,可以通過 -XX:SurvivorRatio 來設(shè)定。
新生代垃圾回收的執(zhí)行過程:
1、Eden 區(qū) + From Survivor 區(qū)存活著的對(duì)象復(fù)制到 To Survivor 區(qū);
2、清空 Eden 和 From Survivor 分區(qū);
3、From Survivor 和 To Survivor 分區(qū)交換(From 變 To,To 變 From)。
老生代(Tenured Generation)
老生代垃圾回收的頻率比新生代低,存放的主要對(duì)象是:
1、新生代對(duì)象經(jīng)過 N 次 GC 晉升到老年代。
可以通過設(shè)置 -XX:MaxTenuringThreshold=5 來設(shè)置,默認(rèn)值是 15 次。
2、大對(duì)象直接存儲(chǔ)到老生代。
所謂的“大對(duì)象”指的是需要連續(xù)存儲(chǔ)空間的對(duì)象,比如:數(shù)組。
當(dāng)大對(duì)象在新生代存儲(chǔ)不下的時(shí)候,就需要分配擔(dān)保機(jī)制,把當(dāng)前新生代的所有對(duì)象復(fù)制到老年代中,因?yàn)榉峙鋼?dān)保機(jī)制需要涉及大量的復(fù)制,會(huì)導(dǎo)致性能問題,所有最好的方案是直接把大對(duì)象存儲(chǔ)到老生代中。
通過參數(shù) -xx:PretrnureSizeThreshold 來設(shè)定大對(duì)象的值。
注意:該參數(shù)只有 Serial 和 ParNew 垃圾回收器有效。
Serial
Serial 最早的垃圾回收器,JDK 1.3.1 之前新生代唯一的垃圾回收器,使用的是單線程串行回收方式,在單 CPU 環(huán)境下性能較好,因?yàn)閱尉€程執(zhí)行不存在線程切換。
線程類型: 單線程
使用算法: 復(fù)制算法
指定收集器: -XX:+UseSerialGC
Serial Old
Serial 收集器的老年代版本,同樣也是單線程的。它有一個(gè)實(shí)用的用途作為CMS收集器的備選預(yù)案,后面介紹CMS的時(shí)候會(huì)詳細(xì)介紹。
線程類型: 單線程
使用算法: 標(biāo)記-整理
指定收集器: -XX:+UseSerialGC
ParNew
ParNew 其實(shí)就是 Serial 的多線程版本,可以和 Serial 共用很多控制參數(shù),比如:-XX:SurvivorRatio , ParNew 可以和 CMS 配合使用。
(注:圖片來源于零壹技術(shù)棧)
線程類型: 多線程
使用算法: 復(fù)制
指定收集器: -XX:+UseParNewGC
Parallel Scavenge
Parallel 和 ParNew 收集器類似,也是多線程的,但 Parallel 是吞吐量?jī)?yōu)先的收集器,GC停頓時(shí)間的縮短是以吞吐量為代價(jià)的,比如收集 100MB 的內(nèi)存,需要 10S 的時(shí)間,CMS 則會(huì)縮短為 7S 收集 50 MB 的內(nèi)存,這樣停頓的時(shí)間確實(shí)縮少了,但收集的頻率變大了,吞吐量就變小了。
線程類型: 多線程
使用算法: 復(fù)制
指定收集器: -XX:+UseParallelGC
Parallel Old
Parallel Old 是 Parallel 的老生代版本,同樣是吞吐量?jī)?yōu)先的收集器。
線程類型: 多線程
使用算法: 標(biāo)記-整理
指定收集器: -XX:+UseParallelOldGC
CMS
CMS(Concurrent Mark Sweep)一種以獲得最短停頓時(shí)間為目標(biāo)的收集器,非常適用B/S系統(tǒng)。
使用 Serial Old 整理內(nèi)存。
CMS 運(yùn)行過程:
(注:圖片來源于零壹技術(shù)棧)
1、初始標(biāo)記
標(biāo)記 GC Roots 直接關(guān)聯(lián)的對(duì)象,需要 Stop The World 。
2、并發(fā)標(biāo)記
從 GC Roots 開始對(duì)堆進(jìn)行可達(dá)性分析,找出活對(duì)象。
3、重新標(biāo)記
重新標(biāo)記階段為了修正并發(fā)期間由于用戶進(jìn)行運(yùn)作導(dǎo)致的標(biāo)記變動(dòng)的那一部分對(duì)象的標(biāo)記記錄。這個(gè)階段的停頓時(shí)間一般會(huì)比初始標(biāo)記階段稍長(zhǎng)一些,但遠(yuǎn)比并發(fā)標(biāo)記的時(shí)間短,也需要 Stop The World 。
4、并發(fā)清除
除垃圾對(duì)象。
CMS 缺點(diǎn):
1、對(duì) CPU 資源要求敏感。
CMS 回收器過分依賴于多線程環(huán)境,默認(rèn)情況下,開啟的線程數(shù)為(CPU 的數(shù)量 + 3)/ 4,當(dāng) CPU 數(shù)量少于 4 個(gè)時(shí),CMS 對(duì)用戶本身的操作的影響將會(huì)很大,因?yàn)橐殖鲆话氲倪\(yùn)算能力去執(zhí)行回收器線程。
2、CMS無法清除浮動(dòng)垃圾。
浮動(dòng)垃圾指的是CMS清除垃圾的時(shí)候,還有用戶線程產(chǎn)生新的垃圾,這部分未被標(biāo)記的垃圾叫做“浮動(dòng)垃圾”,只能在下次 GC 的時(shí)候進(jìn)行清除。
3、CMS 垃圾回收會(huì)產(chǎn)生大量空間碎片。
CMS 使用的是標(biāo)記-清除算法,所有在垃圾回收的時(shí)候回產(chǎn)生大量的空間碎片。
注意:CMS 收集器中,當(dāng)老生代中的內(nèi)存使用超過一定的比例時(shí),系統(tǒng)將會(huì)進(jìn)行垃圾回收;當(dāng)剩余內(nèi)存不能滿足程序運(yùn)行要求時(shí),系統(tǒng)將會(huì)出現(xiàn) Concurrent Mode Failure,臨時(shí)采用 Serial Old 算法進(jìn)行清除,此時(shí)的性能將會(huì)降低。
線程類型: 多線程
使用算法: 標(biāo)記-清除
指定收集器: -XX:+UseConcMarkSweepGC
G1
G1 GC 這是一種兼顧吞吐量和停頓時(shí)間的 GC 實(shí)現(xiàn),是 JDK 9 以后的默認(rèn) GC 選項(xiàng)。G1 可以直觀的設(shè)定停頓時(shí)間的目標(biāo),相比于 CMS GC,G1 未必能做到 CMS 在最好情況下的延時(shí)停頓,但是最差情況要好很多。
G1 GC 仍然存在著年代的概念,但是其內(nèi)存結(jié)構(gòu)并不是簡(jiǎn)單的條帶式劃分,而是類似棋盤的一個(gè)個(gè) region。Region 之間是復(fù)制算法,但整體上實(shí)際可看作是標(biāo)記 - 整理(Mark-Compact)算法,可以有效地避免內(nèi)存碎片,尤其是當(dāng) Java 堆非常大的時(shí)候,G1 的優(yōu)勢(shì)更加明顯。
G1 吞吐量和停頓表現(xiàn)都非常不錯(cuò),并且仍然在不斷地完善,與此同時(shí) CMS 已經(jīng)在 JDK 9 中被標(biāo)記為廢棄(deprecated),所以 G1 GC 值得深入掌握。
G1 運(yùn)行過程:
1、初始標(biāo)記
標(biāo)記 GC Roots 直接關(guān)聯(lián)的對(duì)象,需要 Stop The World 。
2、并發(fā)標(biāo)記
從 GC Roots 開始對(duì)堆進(jìn)行可達(dá)性分析,找出活對(duì)象。
3、重新標(biāo)記
重新標(biāo)記階段為了修正并發(fā)期間由于用戶進(jìn)行運(yùn)作導(dǎo)致的標(biāo)記變動(dòng)的那一部分對(duì)象的標(biāo)記記錄。這個(gè)階段的停頓時(shí)間一般會(huì)比初始標(biāo)記階段稍長(zhǎng)一些,但遠(yuǎn)比并發(fā)標(biāo)記的時(shí)間短,也需要 Stop The World 。
4、篩選回收
首先對(duì)各個(gè) Region 的回收價(jià)值和成本進(jìn)行排序,根據(jù)用戶所期望的 GC 停頓時(shí)間來制定回收計(jì)劃。這個(gè)階段可以與用戶程序一起并發(fā)執(zhí)行,但是因?yàn)橹换厥找徊糠?Region,時(shí)間是用戶可控制的。
線程類型: 多線程
使用算法: 復(fù)制、標(biāo)記-整理
指定收集器: -XX:+UseG1GC(JDK 7u4 版本后可用)
最后:本文歡迎任何形式的轉(zhuǎn)載,如需開通白名單,請(qǐng)?jiān)谠u(píng)論區(qū)留下公眾號(hào)ID即可。
參考
【End】
查看更多面試題內(nèi)容,請(qǐng)?jiān)L問《Java最常見200+面試題全解析》,它包含的模塊有:
Java、JVM?最常見面試題解析
Spring、Spring?MVC、MyBatis、Hibernate?面試題解析
MySQL、Redis?面試題解析
RabbitMQ、Kafka、Zookeeper?面試解析
微服務(wù)?Spring?Boot、Spring?Cloud?面試解析
掃描下面二維碼付費(fèi)閱讀
關(guān)注下方二維碼,訂閱更多精彩內(nèi)容。
轉(zhuǎn)發(fā)朋友圈,是對(duì)我最大的支持。
總結(jié)
以上是生活随笔為你收集整理的经典面试题 | 讲一下垃圾回收器都有哪些?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 面试系列第1篇:常见面试题和面试套路有哪
- 下一篇: 面试官 | count(1)、count