聊聊Java 中的經典垃圾回收器
走過路過不要錯過
點擊 藍字 關注我們
從不同角度分析垃圾收集器,可以將其劃分為不同的模型。
按線程數(shù)分,可以分為串行垃圾回收器和并行垃圾回收器;按照工作模式分,可以分為并發(fā)式垃圾回收器和獨占式垃圾回收器;按碎片處理方式可分為壓縮式垃圾回收器和非壓縮式垃圾回收器;而按工作的內存區(qū)間,又可分為新生代垃圾回收器和老年代垃圾回收器。本文就基于工作的內存區(qū)間劃分,來介紹七種經典的垃圾回收器,下圖是它們的工作區(qū)間以及搭配方式。

Young generation
Serial 收集器
看名字就能猜到,這個收集器是一個單線程工作的收集器,但是它的“單線程”的意義并不僅僅是說明它只會使用一個處理器或一條收集線程去完成垃圾收集工作,更重要的是強調在它進行垃圾收集時,必須暫停其他所有工作線程,直到它工作結束。同時,其采用的是標記復制算法。
Serial 是 JDK 1.3.1 之前新生代的唯一選擇,雖然看起來這個垃圾收集器好像老而無用了。但是事實上它依然是 HotSpot 虛擬機運行在客戶端模式下的默認新生代垃圾收集器,有著優(yōu)于其他收集器的地方,那就是簡單而高效(與其他收集器的單線程相比),對于內存資源受限的環(huán)境,它是所有收集器里額外內存消耗(Memory Footprint)最小的;
ParNew 收集器
ParNew 收集器實際上是 Serial 收集器的多線程并行版本,除了同時使用多條線程進行垃圾收集之外,其余的行為包括 Serial 收集器可用的所有控制參數(shù)、收集算法、Stop The World、對象分配規(guī)則、回收策略等都與 Serial 收集器完全一一致。
ParNew 收集器除了支持多線程并行收集外,其他與 Serial 收集器相比并沒有太多的創(chuàng)新之處,但它卻是不少運行在服務端模式下的 HotSpot 虛擬機,尤其是 JDK 7 之前的遺留系統(tǒng)首選的新生代收集器,其中有一個與功能、性能無關但其實很重要的原因:除了 Serial 收集器外,目前只有它能與 CMS 收集器配合工作。
ParNew 收集器在單核心處理器的環(huán)境中絕對不會有比 Serial 收集器更好的效果。它默認開啟的收集線程與處理核心數(shù)量相同,在處理器核心非常多的環(huán)境下,可以使用?
-XX:ParallelGCThreads
?來限制垃圾回收器的線程數(shù)。
Parallel Scavenge 收集器 #
Parallel Scavenge 收集器也是一款新生代收集器,同樣是基于標記-復制算法實現(xiàn)的收集器,其從表面上看與 ParNew 十分相似,但它的關注點與其他收集器不同,CMS 等收集器的關注點是盡可能地縮短垃圾收集時用戶線程的停頓時間,而?
Parallel Scavenge
?收集器的目標則是達到一個可控制的吞吐量(Throughput)。
所謂吞吐量就是處理器用于運行用戶代碼的時間與處理器總消耗的時間的比值,即:

Tenured generation#
Serial Old 收集器#
Serial Old 是 Serial 收集器的老年代版本,同樣也是一個單線程工作的收集器,使用標記整理算法。
這個收集器的主要意義也是提供客戶端模式下的 HotSpot 虛擬機使用。如果在服務端模式下,它也可能有兩種用途:一種是在 JDK 5 以前的版本中與 Parallel Scavenge 收集器搭配使用,另外一種就是做為 CMS 收集器發(fā)生失敗時的后備預案,在并發(fā)收集發(fā)生 Concurrent Mode Failure 時使用。
Parallel Old 收集器
Parallel Old 是 Parallel Scavenge 收集器的老年代版本,支持多線程并發(fā)收集,基于標記整理算法。
其主要與 Parallel Scavenge 做搭配。
CMS 收集器#
CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器。從名字上就可以看出 CMS 收集器是基于標記-清除算法實現(xiàn)的,它的運作過程相對于前面幾種收集器來說要更復雜一些,整個過程分為四個步驟,包括:
-
初始標記(CMS initial mark)
-
并發(fā)標記(CMS concurrent mark)
-
重新標記(CMS remark)
-
并發(fā)標記(CMS concurrent sweep)
其中并發(fā)標記以及重新標記這兩個步驟仍然需要“Stop The World”。
初始標記僅僅只是標記一下GC Roots能直接關聯(lián)到的對象,速度很快;
并發(fā)標記就是從GC Roots的直接關聯(lián)對象開始遍歷整個對象圖的過程,這個過程耗時很長但是不需要停頓用戶線程,可以與垃圾收集線程一起并發(fā)運行;
而重新標記階段則是為了修正并發(fā)標記期間,因用戶程序繼續(xù)運作而導致標記產生變動的那一部分對象的標記記錄,這個階段的停頓時間通常會比初始標記階段稍微長一些,但也遠比并發(fā)標記階段的時間短;
最后是并發(fā)清除階段,清除刪除掉標記階段判斷的已經死亡的對象,由于不需要移動存活對象,所以這個階段也是可以與用戶線程并發(fā)進行的。
CMS 的優(yōu)點很明顯:并發(fā)收集、低停頓。但它也有很明顯的缺點:
-
CMS收集器對處理器資源非常敏感。事實上,面向并發(fā)設計的程序都對處理器資源比較敏感。在并發(fā)階段,它雖然不會導致用戶線程停頓,但卻會因為占用了一部分線程(或者說處理器的計算能力)而導致應用線程變慢,降低總吞吐量。
-
由于CMS收集器無法處理“浮動垃圾”(Floating Garbage),有可能出現(xiàn)”Concurrent Mode Failure“失敗進而導致另一次完全”Stop The World“的 Full GC 的產生。
浮動垃圾:并發(fā)清理階段用戶線程還在運行,這段時間內就可能產生新的垃圾,新的垃圾在此次 GC 無法清除,只能等到下次清理。這些垃圾有個專業(yè)的名詞:浮動垃圾;
-
CMS 是一款基于”標記-清除“的算法實現(xiàn)的垃圾收集器,這意味著收集結束時會有大量的空間碎片產生。空間碎片過多時,將會給大對象的分配帶來很大的麻煩,往往會出現(xiàn)老年代還有很多剩余空間,但就是無法找到足夠大的連續(xù)空間來分配當前對象。
Garbage First
為解決CMS算法產生空間碎片和其它一系列的問題缺陷,HotSpot提供了另外一種垃圾回收策略,G1(Garbage First)算法,通過參數(shù)
-XX:+UseG1GC
來啟用,該算法在JDK 7u4版本被正式推出,官網對此描述如下:
The Garbage-First (G1) collector is a server-style garbage collector, targeted for multi-processor machines with large memories. It meets garbage collection (GC) pause time goals with a high probability, while achieving high throughput. The G1 garbage collector is fully supported in Oracle JDK 7 update 4 and later releases. The G1 collector is designed for applications that:
Can operate concurrently with applications threads like the CMS collector.
Compact free space without lengthy GC induced pause times.
Need more predictable GC pause durations.
Do not want to sacrifice a lot of throughput performance.
Do not require a much larger Java heap.
在 G1 算法中,采用了另外一種完全不同以往的組織堆內存,堆內存被劃分為多個大小相等的內存塊(Region),每個Region是邏輯連續(xù)的一段內存,結構如下:

每個Region被標記了E、S、O和H,說明每個Region在運行時都充當了一種角色,其中H是以往算法中沒有的,它代表Humongous,這表示這些Region存儲的是巨型對象(humongous object,H-obj),當新建對象大小超過Region大小一半時,直接在新的一個或多個連續(xù)Region中分配,并標記為H。
G1 中提供了三種模式垃圾回收模式,young GC、mixed GC 和 full GC,在不同的條件下被觸發(fā)。
Young GC
發(fā)生在年輕代的GC算法,一般對象(除了巨型對象)都是在eden region中分配內存,當所有eden region被耗盡無法申請內存時,就會觸發(fā)一次 Young GC,這種觸發(fā)機制和之前的 young GC 差不多,執(zhí)行完一次 Young GC,活躍對象會被拷貝到survivor region或者晉升到old region中,空閑的region會被放入空閑列表中,等待下次被使用。
Mixed GC
當越來越多的對象晉升到老年代old region時,為了避免堆內存被耗盡,虛擬機會觸發(fā)一個混合的垃圾收集器,即 mixed gc,該算法并不是一個 Old GC,除了回收整個 Young region,還會回收一部分的 Old Region,這里需要注意:是一部分老年代,而不是全部老年代,可以選擇哪些 Old region 進行收集,從而可以對垃圾回收的耗時時間進行控制。
mixed GC 的執(zhí)行過程有點類似 CMS,主要分為以下幾個步驟:
-
initial mark: 初始標記過程,整個過程 STW,標記了從GC Root可達的對象
-
concurrent marking: 并發(fā)標記過程,整個過程 GC collector線程與應用線程可以并行執(zhí)行,標記出GC Root可達對象衍生出去的存活對象,并收集各個Region的存活對象信息
-
remark: 最終標記過程,整個過程 STW,標記出那些在并發(fā)標記過程中遺漏的,或者內部引用發(fā)生變化的對象
-
clean up: 垃圾清除過程,如果發(fā)現(xiàn)一個Region中沒有存活對象,則把該 Region 加入到空閑列表中
Full GC
如果對象內存分配速度過快,Mixed GC 來不及回收,導致老年代被填滿,就會觸發(fā)一次 Full GC,G1 的 Full GC 算法就是單線程執(zhí)行的 serial old gc,會導致異常長時間的暫停時間,需要進行不斷的調優(yōu),盡可能的避免 Full GC.
想進大廠的小伙伴請注意,
大廠面試的套路很神奇,
早做準備對大家更有好處,
埋頭刷題效率低,
看面經會更有效率!
小編準備了一份 大廠 常問面經 匯總集

剩下的就不會給大家一展出來了,以上資料按照一下操作即可獲得
——將文章進行 轉發(fā) 和 評論 , 關注公眾號【Java烤豬皮】 ,關注后繼續(xù)后臺回復領取口令“? 666 ?”即可免費領文章取中所提供的資料。
往期精品推薦
騰訊、阿里、滴滴后臺試題匯集總結 — (含答案)
面試:史上最全多線程序面試題!
最新阿里內推Java后端試題
JVM難學?那是因為你沒有真正看完整這篇文章
—
結束
—
關注作者微信公眾號 —? 《JAVA烤豬皮》
了解了更多java后端架構知識以及最新面試寶典
看完本文記得給作者點贊+在看哦~~~大家的支持,是作者來源不斷出文的動力~
