做網(wǎng)站的結(jié)論網(wǎng)站的宣傳推廣方式
文章目錄
- 垃圾回收器發(fā)展史
- 垃圾回收器分類
- 按線程數(shù)分類
- 按工作模式分類
- 按處理方式分類
- 查看默認(rèn)垃圾收集器
- 評估垃圾回收器性能指標(biāo)
- 吞吐量
- 暫停時間
- 吞吐量對比暫停時間
- 7種經(jīng)典的垃圾回收器
- 垃圾回收器與垃圾分代
- 垃圾收集器的組合關(guān)系
- Serial GC
- ParNew GC
- Parallel Scavenge GC
- Serial Old GC
- Parallel Old GC
- CMS
- G1
- ZGC
如果說收集算法是內(nèi)存回收的方法論,那么垃圾收集器就是內(nèi)存回收的具體實(shí)現(xiàn)。
雖然我們對各個收集器進(jìn)行比較,但并非要挑選出一個最好的收集器。因?yàn)橹钡浆F(xiàn)在為止還沒有最好的垃圾收集器出現(xiàn),更加沒有萬能的垃圾收集器,我們能做的就是根據(jù)具體應(yīng)用場景選擇適合自己的垃圾收集器。
垃圾回收器發(fā)展史
垃圾收集器是和JVM一脈相承的,它是和JVM進(jìn)行搭配使用,在不同的使用場景對應(yīng)的收集器也是有區(qū)別。有了虛擬機(jī),就一定需要收集垃圾的機(jī)制,這就是Garbage Collection
,對應(yīng)的產(chǎn)品我們稱為Garbage Collector
。
經(jīng)典GC:
- 1999年隨JDK1.3.1一起來的是串行方式的serialGc,它是第一款GC。ParNew垃圾收集器是Serial收集器的多線程版本。
- 2002年2月26日,
Parallel GC
和Concurrent Mark Sweep GC
跟隨JDK1.4.2一起發(fā)布。 Parallel GC
在JDK6之后成為HotSpot默認(rèn)GC。- 2012年,在JDK1.7u4版本中,G1可用。
- 2017年,JDK9中G1變成默認(rèn)的垃圾收集器,以替代CMS。
- 2018年3月,JDK10中G1垃圾回收器的并行完整垃圾回收,實(shí)現(xiàn)并行性來改善最壞情況下的延遲。
高性能GC:
- 2018年9月,JDK11發(fā)布。引入
Epsilon
垃圾回收器,又被稱為 "No-Op(無操作)“ 回收器。同時,引入ZGC:可伸縮的低延遲垃圾回收器(Experimental) - 2019年3月,JDK12發(fā)布。增強(qiáng)G1,自動返回未用堆內(nèi)存給操作系統(tǒng)。同時,引入
Shenandoah GC
:低停頓時間的GC(Experimental)。·2019年9月,JDK13發(fā)布。增強(qiáng)ZGC,自動返回未用堆內(nèi)存給操作系統(tǒng)。 - 2020年3月,JDK14發(fā)布。刪除CMS垃圾回收器。擴(kuò)展zGC在 MacOS 和 Windows 上的應(yīng)用
垃圾回收器分類
垃圾收集器沒有在規(guī)范中進(jìn)行過多的規(guī)定,可以由不同的廠商、不同版本的JVM來實(shí)現(xiàn)。
由于JDK的版本處于高速迭代過程中,因此Java發(fā)展至今已經(jīng)衍生了眾多的GC版本。從不同角度分析垃圾收集器,可以將GC分為不同的類型。
按線程數(shù)分類
-
串行垃圾回收器:在單核CPU的硬件情況下,該收集器會在工作時凍結(jié)所有應(yīng)用程序線程,這使它在所有目的和用途上都無法在服務(wù)器環(huán)境中使用。
-
并行垃圾回收器:在停止用戶線程之后,多條GC線程并行進(jìn)行垃圾回收。和串行回收相反,并行收集可以運(yùn)用多個CPU同時執(zhí)行垃圾回收,因此提升了應(yīng)用的吞吐量。
按工作模式分類
-
并發(fā)式垃圾回收器:不會出現(xiàn)STW現(xiàn)象,指多條垃圾收集線程同時進(jìn)行工作,GC線程和用戶線程同時運(yùn)行,不會出現(xiàn)STW現(xiàn)象。
-
獨(dú)占式垃圾回收器:會出現(xiàn)STW現(xiàn)象,一旦運(yùn)行,就停止應(yīng)用程序中的所有用戶線程,直到垃圾回收過程完全結(jié)束。
按處理方式分類
- 壓縮式垃圾回收器:壓縮式垃圾回收器會在回收完成后,對存活對象進(jìn)行壓縮整理,消除回收后的碎片。所以在為對象分配內(nèi)存的時候用指針碰撞;
- 非壓縮式垃圾回收器:非壓縮式的垃圾回收器不進(jìn)行整理這步操作。所以在為為對象分配內(nèi)存的時候使用空閑列表;
查看默認(rèn)垃圾收集器
JDK 默認(rèn)垃圾收集器(使用 java -XX:+PrintCommandLineFlags -version 命令查看):
- JDK 8:Parallel Scavenge(新生代)+ Parallel Old(老年代)
- JDK 9 ~ JDK20: G1
使用虛擬機(jī)參數(shù)-XX:+PrintCommandLineFlags
,查看命令行相關(guān)參數(shù)。
運(yùn)行下列程序
public class MainTest {public static void main(String[] args) {try {Thread.sleep(100000);} catch (InterruptedException e) {e.printStackTrace();}}
}
輸出結(jié)果
-XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4294967296 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
使用命令行指令:jinfo -flag
評估垃圾回收器性能指標(biāo)
- 吞吐量:運(yùn)行用戶代碼的時間占總運(yùn)行時間的比例(總運(yùn)行時間 = 程序的運(yùn)行時間 + 內(nèi)存回收的時間)。
- 垃圾收集開銷:吞吐量的補(bǔ)數(shù),垃圾收集所用時間與總運(yùn)行時間的比例。
- 暫停時間:執(zhí)行垃圾收集時,程序的工作線程被暫停的時間。
- 收集頻率:相對于應(yīng)用程序的執(zhí)行,收集操作發(fā)生的頻率。
- 內(nèi)存占用:Java堆區(qū)所占的內(nèi)存大小。
- 快速:一個對象從誕生到被回收所經(jīng)歷的時間。
吞吐量、暫停時間、內(nèi)存占用 這三者共同構(gòu)成一個“不可能三角”。這三項(xiàng)里,暫停時間的重要性日益凸顯。因?yàn)殡S著硬件發(fā)展,內(nèi)存占用多些越來越能容忍,硬件性能的提升也有助于降低收集器運(yùn)行時對應(yīng)用程序的影響,即提高了吞吐量。而內(nèi)存的擴(kuò)大,對延遲反而帶來負(fù)面效果。
一款優(yōu)秀的收集器通常最多同時滿足其中的兩項(xiàng),簡單來說,主要抓住吞吐量、暫停時間這兩點(diǎn)。
吞吐量
吞吐量就是CPU用于運(yùn)行用戶代碼的時間與CPU總消耗時間的比值。吞吐量=運(yùn)行用戶代碼時間 /(運(yùn)行用戶代碼時間+垃圾收集時間)
在注重吞吐量的這種情況下,應(yīng)用程序能容忍較高的暫停時間,因此,高吞吐量的應(yīng)用程序有更長的時間基準(zhǔn),快速響應(yīng)是不必考慮的。吞吐量優(yōu)先,意味著在單位時間內(nèi),STW的時間最短。
暫停時間
暫停時間是指一個時間段內(nèi)應(yīng)用程序線程暫停,讓GC線程執(zhí)行的狀態(tài),它關(guān)系著用戶的體驗(yàn)。例如,GC期間100毫秒的暫停時間意味著在這100毫秒期間內(nèi)沒有應(yīng)用程序線程是活動的。暫停時間優(yōu)先,意味著盡可能讓單次STW的時間最短。
吞吐量對比暫停時間
高吞吐量較好,因?yàn)檫@會讓應(yīng)用程序的最終用戶感覺只有應(yīng)用程序線程在做“生產(chǎn)性”工作,直覺上吞吐量越高程序運(yùn)行越快。
低暫停時間較好因?yàn)閺淖罱K用戶的角度來看不管是GC還是其他原因?qū)е乱粋€應(yīng)用被掛起始終是不好的。這取決于應(yīng)用程序的類型,有時候甚至短暫的200毫秒暫停都可能打斷終端用戶體驗(yàn)。因此,具有低的較大暫停時間是非常重要的,特別是對于一個交互式應(yīng)用程序。
不幸的是”高吞吐量”和”低暫停時間”是相互矛盾的。
因?yàn)槿绻x擇以吞吐量優(yōu)先,那么必然需要降低內(nèi)存回收的執(zhí)行頻率,但是這樣會導(dǎo)致GC需要更長的暫停時間來執(zhí)行內(nèi)存回收。相反的,如果選擇以低延遲優(yōu)先為原則,那么為了降低每次執(zhí)行內(nèi)存回收時的暫停時間,也只能頻繁地執(zhí)行內(nèi)存回收,但這又引起了年輕代內(nèi)存的縮減和導(dǎo)致程序吞吐量的下降。
所以,在設(shè)計(jì)或使用GC算法時,我們必須確定我們的目標(biāo):一個GC算法只可能針對兩個目標(biāo)之一即只專注于較大吞吐量或最小暫停時間,或嘗試找到一個二者的折中。
7種經(jīng)典的垃圾回收器
- 串行回收器:
Serial
、Serial old
- 并行回收器:
ParNew
、Parallel Scavenge
、Parallel old
- 并發(fā)回收器:
CMS
、G1
、ZGC
垃圾回收器與垃圾分代
- 新生代收集器:
Serial
、ParNew
、Parallel Scavenge
- 老年代收集器:
Serial old
、Parallel old
、CMS
- 整堆收集器:
G1
、ZGC
垃圾收集器的組合關(guān)系
- 兩個收集器間有連線,表明它們可以搭配使用
Serial/Serial old
Serial/CMS
ParNew/Serial old
、ParNew/CMS、Parallel
Scavenge/Serial 0ld
Parallel Scavenge/Parallel old
G1
Serial old
和CMS
之間的連線表示,Serial old
作為CMS出現(xiàn)"Concurrent Mode Failure"失敗的后備預(yù)案- 紅色虛線表示,在JDK 8時將
Serial + CMS
、ParNew + Serial old
這兩個組合聲明為廢棄;并在JDK9中完全取消了這些組合的支持 - 綠色虛線表示,JDK14中:棄用
Parallel Scavenge
和Serial old
組合 - 青色虛線表示,在JDK14中刪除CMS垃圾回收器
為什么要有很多垃圾回收器?
因?yàn)槔厥掌鳑]有最好的實(shí)現(xiàn),想要STW時間段的就需要吞吐量少一點(diǎn);所以我們選擇的只是對具體應(yīng)用最合適的收集器。針對不同的場景,提供不同的垃圾收集器,來提高垃圾收集的性能。
Serial GC
Serial GC
由于弊端較大,只有放在單核CPU上才能充分發(fā)揮其作用,由于現(xiàn)在都是多核CPU已經(jīng)不用串行收集器了,所以以下內(nèi)容了解即可。對于交互較強(qiáng)的應(yīng)用而言,這種垃圾收集器是不能接受的。一般在Java web應(yīng)用程序中是不會采用串行垃圾收集器的。
Serial GC
(串行垃圾回收回器)是最基本、歷史最悠久的垃圾收集器了。JDK1.3之前回收新生代唯一的選擇。
Serial GC
作為HotSpot中client模式下的默認(rèn)新生代垃圾收集器;Serial GC
年輕代采用標(biāo)記-復(fù)制算法,老年代采用標(biāo)記-整理算法、串行回收和STW機(jī)制的方式執(zhí)行內(nèi)存回收。
Serial GC
是一個單線程的收集器,但它的“單線程”的意義并不僅僅說明它只會使用一個CPU或一條收集線程去完成垃圾收集工作,更重要的是在它進(jìn)行垃圾收集時,必須暫停其他所有的工作線程,直到它收集結(jié)束。
Serial GC
的優(yōu)點(diǎn), 簡單而高效(與其他收集器的單線程比),對于限定單個CPU的環(huán)境來說,Serial GC
由于沒有線程交互的開銷,專心做垃圾收集自然可以獲得最高的單線程收集效率。是運(yùn)行在client模式下的虛擬機(jī)是個不錯的選擇。
運(yùn)行任意程序,設(shè)置虛擬機(jī)參數(shù)如下,當(dāng)設(shè)置使用Serial GC
時,新生代和老年代都會使用串行收集器。
-XX:+PrintCommandLineFlags -XX:+UseSerialGC
輸出
-XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4294967296 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseSerialGC
ParNew GC
ParNew 收集器其實(shí)就是 Serial 收集器的多線程版本,除了使用多線程進(jìn)行垃圾收集外,其余行為:控制參數(shù)、收集算法、回收策略等等和 Serial 收集器完全一樣。
它是許多運(yùn)行在 Server 模式下的虛擬機(jī)的首要選擇,除了 Serial 收集器外,只有它能與 CMS 收集器配合工作。
Parallel Scavenge GC
Parallel Scavenge 收集器也是使用標(biāo)記-復(fù)制算法的多線程收集器,它看上去幾乎和 ParNew 都一樣。
Parallel Scavenge 收集器關(guān)注點(diǎn)是吞吐量(高效率的利用 CPU)。CMS 等垃圾收集器的關(guān)注點(diǎn)更多的是用戶線程的停頓時間(提高用戶體驗(yàn))。
Serial Old GC
Serial 收集器的老年代版本,它同樣是一個單線程收集器。它主要有兩大用途:
- 在 JDK1.5 以及以前的版本中與 Parallel Scavenge 收集器搭配使用;
- 作為 CMS 收集器的后備方案;
Parallel Old GC
Parallel Scavenge 收集器的老年代版本。使用多線程和“標(biāo)記-整理”算法。在注重吞吐量以及 CPU 資源的場合,都可以優(yōu)先考慮 Parallel Scavenge 收集器和 Parallel Old 收集器。
CMS
CMS全稱:Concurrent Mark Sweep,是一種以獲取最短回收停頓時間為目標(biāo)的收集器。它非常符合在注重用戶體驗(yàn)的應(yīng)用上使用。CMS收集器是 HotSpot 虛擬機(jī)第一款真正意義上的并發(fā)收集器,它第一次實(shí)現(xiàn)了讓垃圾收集線程與用戶線程(基本上)同時工作。
從名字中的Mark Sweep這兩個詞可以看出,CMS 收集器是一種 “標(biāo)記-清除”算法實(shí)現(xiàn)的,以獲取最短回收停頓時間為目標(biāo),采用“標(biāo)記-清除”算法,分 4 大步進(jìn)行垃圾收集,其中初始標(biāo)記和重新標(biāo)記會 STW,JDK 1.5 時引入,JDK9 被標(biāo)記棄用,JDK14 被移除。
- 初始標(biāo)記,指的是尋找所有被 GCRoots 引用的對象,該階段需要「Stop the World」。這個步驟僅僅只是標(biāo)記一下 GC Roots 能直接關(guān)聯(lián)到的對象,并不需要做整個引用的掃描,因此速度很快。
- 并發(fā)標(biāo)記,指的是對「初始標(biāo)記階段」標(biāo)記的對象進(jìn)行整個引用鏈的掃描,該階段不需要「Stop the World」。 對整個引用鏈做掃描需要花費(fèi)非常多的時間,因此需要通過垃圾回收線程與用戶線程并發(fā)執(zhí)行,降低垃圾回收的時間,所以叫做并發(fā)標(biāo)記。這也是 CMS 能極大降低 GC 停頓時間的核心原因,但這也帶來了一些問題,即:并發(fā)標(biāo)記的時候,引用可能發(fā)生變化,因此可能發(fā)生漏標(biāo)(本應(yīng)該回收的垃圾沒有被回收)和多標(biāo)(本不應(yīng)該回收的垃圾被回收)了。
- 重新標(biāo)記,指的是對「并發(fā)標(biāo)記」階段出現(xiàn)的問題進(jìn)行校正,該階段需要「Stop the World」。正如并發(fā)標(biāo)記階段說到的,由于垃圾回收算法和用戶線程并發(fā)執(zhí)行,雖然能降低響應(yīng)時間,但是會發(fā)生漏標(biāo)和多標(biāo)的問題。所以對于 CMS 來說,它需要在這個階段做一些校驗(yàn),解決并發(fā)標(biāo)記階段發(fā)生的問題。
- 并發(fā)清除,指的是將標(biāo)記為垃圾的對象進(jìn)行清除,該階段不需要「Stop the World」。 在這個階段,垃圾回收線程與用戶線程可以并發(fā)執(zhí)行,因此并不影響用戶的響應(yīng)時間。
CMS 的優(yōu)點(diǎn)是:并發(fā)收集、低停頓,但缺點(diǎn)也很明顯:
- 對 CPU 資源非常敏感,因此在 CPU 資源緊張的情況下,CMS 的性能會大打折扣。默認(rèn)情況下,CMS 啟用的垃圾回收線程數(shù)是(CPU數(shù)量 + 3)/4,當(dāng) CPU 數(shù)量很大時,啟用的垃圾回收線程數(shù)占比就越小。但如果 CPU 數(shù)量很小,例如只有 2 個 CPU,垃圾回收線程占用就達(dá)到了 50%,這極大地降低系統(tǒng)的吞吐量,無法接受。
- CMS 采用的是「標(biāo)記-清除」算法,會產(chǎn)生大量的內(nèi)存碎片,導(dǎo)致空間不連續(xù),當(dāng)出現(xiàn)大對象無法找到連續(xù)的內(nèi)存空間時,就會觸發(fā)一次 Full GC,這會導(dǎo)致系統(tǒng)的停頓時間變長。
- CMS 無法處理浮動垃圾,當(dāng) CMS 在進(jìn)行垃圾回收的時候,應(yīng)用程序還在不斷地產(chǎn)生垃圾,這些垃圾會在 CMS 垃圾回收結(jié)束之后產(chǎn)生,這些垃圾就是浮動垃圾,CMS 無法處理這些浮動垃圾,只能在下一次 GC 時清理掉。
G1
G1 (Garbage-First) 是一款面向服務(wù)器的垃圾收集器,主要針對配備多顆處理器及大容量內(nèi)存的機(jī)器. 以極高概率滿足 GC 停頓時間要求的同時,還具備高吞吐量性能特征。在 JDK 1.7 時引入,在 JDK 9 時取代 CMS 成為了默認(rèn)的垃圾收集器。G1 有五個屬性:分代、增量、并行、標(biāo)記整理、可預(yù)測的停頓。
-
分代:
將堆內(nèi)存分為多個大小相等的區(qū)域(Region),每個區(qū)域都可以是 Eden 區(qū)、Survivor 區(qū)或者 Old 區(qū)。
可以通過 -XX:G1HeapRegionSize=n 來設(shè)置 Region 的大小,可以設(shè)定為 1M、2M、4M、8M、16M、32M(不能超過)。
G1 有專門分配大對象的 Region 叫 Humongous 區(qū),而不是讓大對象直接進(jìn)入老年代的 Region 中。 在 G1 中,大對象的判定規(guī)則就是一個大對象超過了一個 Region 大小的 50%,比如每個 Region 是 2M,只要一個對象超過了 1M,就會被放入 Humongous 中,而且一個大對象如果太大,可能會橫跨多個 Region 來存放。
G1 會根據(jù)各個區(qū)域的垃圾回收情況來決定下一次垃圾回收的區(qū)域,這樣就避免了對整個堆內(nèi)存進(jìn)行垃圾回收,從而降低了垃圾回收的時間。 -
增量:G1 可以以增量方式執(zhí)行垃圾回收,這意味著它不需要一次性回收整個堆空間,而是可以逐步、增量地清理。有助于控制停頓時間,尤其是在處理大型堆時。
-
并行:G1 垃圾回收器可以并行回收垃圾,這意味著它可以利用多個 CPU 來加速垃圾回收的速度,這一特性在年輕代的垃圾回收(Minor GC)中比較明顯,因?yàn)槟贻p代的回收通常涉及較多的對象和較高的回收速率。
-
標(biāo)記整理:在進(jìn)行老年代的垃圾回收時,G1 使用標(biāo)記-整理算法。這個過程分為兩個階段:標(biāo)記存活的對象和整理(壓縮)堆空間。通過整理,G1 能夠避免內(nèi)存碎片化,提高內(nèi)存利用率。
-
可預(yù)測的停頓:G1 也是基于「標(biāo)記-清除」算法,因此在進(jìn)行垃圾回收的時候,仍然需要「Stop the World」。不過,G1 在停頓時間上添加了預(yù)測機(jī)制,用戶可以指定期望停頓時間。
G1 中存在三種 GC 模式,分別是 Young GC、Mixed GC 和 Full GC。
當(dāng) Eden 區(qū)的內(nèi)存空間無法支持新對象的內(nèi)存分配時,G1 會觸發(fā) Young GC。
當(dāng)需要分配對象到 Humongous 區(qū)域或者堆內(nèi)存的空間占比超過 -XX:G1HeapWastePercent 設(shè)置的 InitiatingHeapOccupancyPercent 值時,G1 會觸發(fā)一次 concurrent marking,它的作用就是計(jì)算老年代中有多少空間需要被回收,當(dāng)發(fā)現(xiàn)垃圾的占比達(dá)到 -XX:G1HeapWastePercent 中所設(shè)置的 G1HeapWastePercent 比例時,在下次 Young GC 后會觸發(fā)一次 Mixed GC。Mixed GC 是指回收年輕代的 Region 以及一部分老年代中的 Region。Mixed GC 和 Young GC 一樣,采用的也是復(fù)制算法。
在 Mixed GC 過程中,如果發(fā)現(xiàn)老年代空間還是不足,此時如果 G1HeapWastePercent 設(shè)定過低,可能引發(fā) Full GC。-XX:G1HeapWastePercent 默認(rèn)是 5,意味著只有 5% 的堆是“浪費(fèi)”的。如果浪費(fèi)的堆的百分比大于 G1HeapWastePercent,則運(yùn)行 Full GC。
在以 Region 為最小管理單元以及所采用的 GC 模式的基礎(chǔ)上,G1 建立了停頓預(yù)測模型,即 Pause Prediction Model 。這也是 G1 非常被人所稱道的特性??梢越柚?-XX:MaxGCPauseMillis 來設(shè)置期望的停頓時間(默認(rèn) 200ms),G1 會根據(jù)這個值來計(jì)算出一個合理的 Young GC 的回收時間,然后根據(jù)這個時間來制定 Young GC 的回收計(jì)劃。
G1收集垃圾的過程:
- 初始標(biāo)記 (Inital Marking) :標(biāo)記 GC Roots 能直接關(guān)聯(lián)到的對象,并且修改 TAMS(Top at Mark Start)指針的值,讓下一階段用戶線程并發(fā)運(yùn)行時,能夠正確的在 Reigin 中分配新對象。
G1 為每一個 Reigin 都設(shè)計(jì)了兩個名為 TAMS 的指針,新分配的對象必須位于這兩個指針位置以上,位于這兩個指針位置以上的對象默認(rèn)被隱式標(biāo)記為存活的,不會納入回收范圍; - 并發(fā)標(biāo)記 (Concurrent Marking) :從 GC Roots 能直接關(guān)聯(lián)到的對象開始遍歷整個對象圖。遍歷完成后,還需要處理 SATB 記錄中變動的對象。
SATB(snapshot-at-the-beginning,開始階段快照)能夠有效的解決并發(fā)標(biāo)記階段因?yàn)橛脩艟€程運(yùn)行而導(dǎo)致的對象變動,其效率比 CMS 重新標(biāo)記階段所使用的增量更新算法效率更高; - 最終標(biāo)記 (Final Marking) :對用戶線程做一個短暫的暫停,用于處理并發(fā)階段結(jié)束后仍遺留下來的少量的 STAB 記錄。雖然并發(fā)標(biāo)記階段會處理 SATB 記錄,但由于處理時用戶線程依然是運(yùn)行中的,因此依然會有少量的變動,所以需要最終標(biāo)記來處理;
- 篩選回收 (Live Data Counting and Evacuation) :負(fù)責(zé)更新 Regin 統(tǒng)計(jì)數(shù)據(jù),按照各個 Regin 的回收價值和成本進(jìn)行排序,在根據(jù)用戶期望的停頓時間進(jìn)行來指定回收計(jì)劃,可以選擇任意多個 Regin 構(gòu)成回收集。
然后將回收集中 Regin 的存活對象復(fù)制到空的 Regin 中,再清理掉整個舊的 Regin 。此時因?yàn)樯婕暗酱婊顚ο蟮囊苿?#xff0c;所以需要暫停用戶線程,并由多個收集線程并行執(zhí)行。
ZGC
ZGC(The Z Garbage Collector)是 JDK11 推出的一款低延遲垃圾收集器,適用于大內(nèi)存低延遲服務(wù)的內(nèi)存管理和回收,SPEC jbb 2015 基準(zhǔn)測試,在 128G 的大堆下,最大停頓時間為 1.68 ms,停頓時間遠(yuǎn)勝于 G1 和 CMS。
ZGC 在 Java11 中引入,處于試驗(yàn)階段。經(jīng)過多個版本的迭代,不斷的完善和修復(fù)問題,ZGC 在 Java15 已經(jīng)可以正式使用了。不過,默認(rèn)的垃圾回收器依然是 G1。你可以通過java -XX:+UseZGC className
啟用 ZGC。
與 G1 和 CMS 類似,ZGC 也采用了復(fù)制算法,只不過做了重大優(yōu)化,ZGC 在標(biāo)記、轉(zhuǎn)移和重定位階段幾乎都是并發(fā)的,這是 ZGC 實(shí)現(xiàn)停頓時間小于 10ms 的關(guān)鍵所在。
關(guān)鍵技術(shù)在于:
- 指針染色(Colored Pointer):一種用于標(biāo)記對象狀態(tài)的技術(shù)。
- 讀屏障(Load Barrier):一種在程序運(yùn)行時插入到對象訪問操作中的特殊檢查,用于確保對象訪問的正確性。
這兩種技術(shù)可以讓所有線程在并發(fā)的條件下,就指針的狀態(tài)達(dá)成一致。因此,ZGC 可以并發(fā)的復(fù)制對象,這大大的降低了 GC 的停頓時間。