微吼云上線多路互動直播服務 加速多場景互動直播落地
754
2025-04-01
垃圾收集器
前言
GC垃圾回收算法和垃圾收集器關系
四種主要的垃圾收集器
Serial
Parallel
CMS
G1
垃圾收集器總結
查看默認垃圾收集器
默認垃圾收集器有哪些
各垃圾收集器的使用范圍
部分參數說明
Java中的Server和Client模式
新生代下的垃圾收集器
串行GC(Serial)
并行GC(ParNew)
并行回收GC(Parallel)/ (Parallel Scavenge)
老年代下的垃圾收集器
串行GC(Serial Old) / (Serial MSC)
并行GC(Parallel Old)/ (Parallel MSC)
并發標記清除GC(CMS)
四個步驟
垃圾收集器如何選擇
組合的選擇
G1垃圾收集器
開啟G1垃圾收集器
以前收集器的特點
G1是什么
特點
底層原理
Region區域化垃圾收集器
回收步驟
四步過程
參數配置
G1和CMS比較
Springboot結合JVMGC
參數配置
G1和CMS比較
Springboot結合JVMGC
總結
前言
最近聽了周陽老師講關于Java垃圾收集器的課,真的獲益頗多,特整理筆記分享,在下面的內容里你可以學習到如下知識:
1、什么是垃圾器、垃圾器的分類及它們的優缺點。
2、主要的GC算法
3、…
GC垃圾回收算法和垃圾收集器關系
天上飛的理念,要有落地的實現(垃圾收集器就是GC垃圾回收算法的實現)
GC算法是內存回收的方法論,垃圾收集器就是算法的落地實現
GC算法主要有以下幾種
引用計數(幾乎不用,無法解決循環引用的問題)
復制拷貝(用于新生代)
標記清除(用于老年代)
標記整理(用于老年代)
因為目前為止還沒有完美的收集器出現,更沒有萬能的收集器,只是針對具體應用最合適的收集器,進行分代收集(那個代用什么收集器)
四種主要的垃圾收集器
Serial:串行回收 -XX:+UseSeriallGC
Parallel:并行回收 -XX:+UseParallelGC
CMS:并發標記清除
G1
ZGC:(java 11 出現的)
Serial
串行垃圾回收器,它為單線程環境設計且值使用一個線程進行垃圾收集,會暫停所有的用戶線程,只有當垃圾回收完成時,才會重新喚醒主線程繼續執行。所以不適合服務器環境
Parallel
并行垃圾收集器,多個垃圾收集線程并行工作,此時用戶線程也是阻塞的,適用于科學計算 / 大數據處理等弱交互場景,也就是說Serial 和 Parallel其實是類似的,不過是多了幾個線程進行垃圾收集,但是主線程都會被暫停,但是并行垃圾收集器處理時間,肯定比串行的垃圾收集器要更短
CMS
并發標記清除,用戶線程和垃圾收集線程同時執行(不一定是并行,可能是交替執行),不需要停頓用戶線程,互聯網公司都在使用,適用于響應時間有要求的場景。并發是可以有交互的,也就是說可以一邊進行收集,一邊執行應用程序。
G1
G1垃圾回收器將堆內存分割成不同區域,然后并發的進行垃圾回收
垃圾收集器總結
注意:并行垃圾回收在單核CPU下可能會更慢
查看默認垃圾收集器
使用下面JVM命令,查看配置的初始參數
-XX:+PrintCommandLineFlags
1
然后運行一個程序后,能夠看到它的一些初始配置信息
-XX:InitialHeapSize=266376000 -XX:MaxHeapSize=4262016000 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
1
移動到最后一句,就能看到 -XX:+UseParallelGC 說明使用的是并行垃圾回收
-XX:+UseParallelGC
1
默認垃圾收集器有哪些
Java中一共有7大垃圾收集器
UserSerialGC:串行垃圾收集器
UserParallelGC:并行垃圾收集器
UseConcMarkSweepGC:(CMS)并發標記清除
UseParNewGC:年輕代的并行垃圾回收器
UseParallelOldGC:老年代的并行垃圾回收器
UseG1GC:G1垃圾收集器
UserSerialOldGC:串行老年代垃圾收集器(已經被移除)
底層源碼
各垃圾收集器的使用范圍
新生代使用的:
Serial Copying: UserSerialGC,串行垃圾回收器
Parallel Scavenge:UserParallelGC,并行垃圾收集器
ParNew:UserParNewGC,新生代并行垃圾收集器
老年區使用的:
Serial Old:UseSerialOldGC,老年代串行垃圾收集器
Parallel Compacting(Parallel Old):UseParallelOldGC,老年代并行垃圾收集器
CMS:UseConcMarkSwepp,并行標記清除垃圾收集器
各區都能使用的:
G1:UseG1GC,G1垃圾收集器
垃圾收集器就來具體實現這些GC算法并實現內存回收,不同廠商,不同版本的虛擬機實現差別很大,HotSpot中包含的收集器如下圖所示:
部分參數說明
DefNew:Default New Generation
Tenured:Old
ParNew:Parallel New Generation
PSYoungGen:Parallel Scavenge
ParOldGen:Parallel Old Generation
Java中的Server和Client模式
使用范圍:一般使用Server模式,Client模式基本不會使用
32位的Window操作系統,不論硬件如何都默認使用Client的JVM模式
32位的其它操作系統,2G內存同時有2個cpu以上用Server模式,低于該配置還是Client模式
64位只有Server模式
新生代下的垃圾收集器
串行GC(Serial)
串行GC(Serial)(Serial Copying)
是一個單線程單線程的收集器,在進行垃圾收集時候,必須暫停其他所有的工作線程直到它收集結束。
串行收集器是最古老,最穩定以及效率高的收集器,只使用一個線程去回收但其在垃圾收集過程中可能會產生較長的停頓(Stop-The-World 狀態)。 雖然在收集垃圾過程中需要暫停所有其它的工作線程,但是它簡單高效,對于限定單個CPU環境來說,沒有線程交互的開銷可以獲得最高的單線程垃圾收集效率,因此Serial垃圾收集器依然是Java虛擬機運行在Client模式下默認的新生代垃圾收集器
對應JVM參數是:-XX:+UseSerialGC
開啟后會使用:Serial(Young區用) + Serial Old(Old區用) 的收集器組合
表示:新生代、老年代都會使用串行回收收集器,新生代使用復制算法,老年代使用標記-整理算法
-Xms10m -Xmx10m -XX:PrintGCDetails -XX:+PrintConmandLineFlags -XX:+UseSerialGC
1
并行GC(ParNew)
并行收集器,使用多線程進行垃圾回收,在垃圾收集,會Stop-the-World暫停其他所有的工作線程直到它收集結束
ParNew收集器其實就是Serial收集器新生代的并行多線程版本,最常見的應用場景時配合老年代的CMS GC工作,其余的行為和Serial收集器完全一樣,ParNew垃圾收集器在垃圾收集過程中同樣也要暫停所有其他的工作線程。它是很多Java虛擬機運行在Server模式下新生代的默認垃圾收集器。
常見對應JVM參數:-XX:+UseParNewGC 啟動ParNew收集器,只影響新生代的收集,不影響老年代
開啟上述參數后,會使用:ParNew(Young區用) + Serial Old的收集器組合,新生代使用復制算法,老年代采用標記-整理算法
-Xms10m -Xmx10m -XX:PrintGCDetails -XX:+PrintConmandLineFlags -XX:+UseParNewGC
1
但是會出現警告,即 ParNew 和 Serial Old 這樣搭配,Java8已經不再被推薦
備注: -XX:ParallelGCThreads 限制線程數量,默認開啟和CPU數目相同的線程數
并行回收GC(Parallel)/ (Parallel Scavenge)
因為Serial 和 ParNew都不推薦使用了,因此現在新生代默認使用的是Parallel Scavenge,也就是新生代和老年代都是使用并行
Parallel Scavenge收集器類似ParNew也是一個新生代垃圾收集器,使用復制算法,也是一個并行的多線程的垃圾收集器,俗稱吞吐量優先收集器。一句話:串行收集器在新生代和老年代的并行化
它關注的重點是:
可控制的吞吐量(Thoughput = 運行用戶代碼時間 / (運行用戶代碼時間 + 垃圾收集時間) ),也即比如程序運行100分鐘,垃圾收集時間1分鐘,吞吐量就是99%。高吞吐量意味著高效利用CPU時間,它多用于在后臺運算而不需要太多交互的任務。
自適應調節策略也是ParallelScavenge收集器與ParNew收集器的一個重要區別。(自適應調節策略:虛擬機會根據當前系統的運行情況收集性能監控信息,動態調整這些參數以提供最合適的停頓時間( -XX:MaxGCPauseMills))或最大的吞吐量。
常用JVM參數:-XX:+UseParallelGC 或 -XX:+UseParallelOldGC(可互相激活)使用Parallel Scanvenge收集器
開啟該參數后:新生代使用復制算法,老年代使用標記-整理算法
-Xms10m -Xmx10m -XX:PrintGCDetails -XX:+PrintConmandLineFlags -XX:+UseParallelGC
1
老年代下的垃圾收集器
串行GC(Serial Old) / (Serial MSC)
Serial Old是Serial垃圾收集器老年代版本,它同樣是一個單線程的收集器,使用標記-整理算法,這個收集器也主要是運行在Client默認的Java虛擬機中默認的老年代垃圾收集器
在Server模式下,主要有兩個用途(了解,版本已經到8及以后)
在JDK1.5之前版本中與新生代的Parallel Scavenge收集器搭配使用(Parallel Scavenge + Serial Old)
作為老年代版中使用CMS收集器的后備垃圾收集方案。
配置方法:
-Xms10m -Xmx10m -XX:PrintGCDetails -XX:+PrintConmandLineFlags -XX:+UseSerialOldlGC
1
該垃圾收集器,目前已經不推薦使用了
并行GC(Parallel Old)/ (Parallel MSC)
Parallel Old收集器是Parallel Scavenge的老年代版本,使用多線程的標記-整理算法,Parallel Old收集器在JDK1.6才開始提供。
在JDK1.6之前,新生代使用ParallelScavenge收集器只能搭配老年代的Serial Old收集器,只能保證新生代的吞吐量優先,無法保證整體的吞吐量。在JDK1.6以前(Parallel Scavenge + Serial Old)
Parallel Old正是為了在老年代同樣提供吞吐量優先的垃圾收集器,如果系統對吞吐量要求比較高,JDK1.8后可以考慮新生代Parallel Scavenge和老年代Parallel Old 收集器的搭配策略。在JDK1.8及后(Parallel Scavenge + Parallel Old)
JVM常用參數:
-XX +UseParallelOldGC:使用Parallel Old收集器,設置該參數后,新生代Parallel+老年代 Parallel Old
1
使用老年代并行收集器:
-Xms10m -Xmx10m -XX:PrintGCDetails -XX:+PrintConmandLineFlags -XX:+UseParallelOldlGC
1
并發標記清除GC(CMS)
CMS收集器(Concurrent Mark Sweep:并發標記清除)是一種以最短回收停頓時間為目標的收集器
適合應用在互聯網或者B/S系統的服務器上,這類應用尤其重視服務器的響應速度,希望系統停頓時間最短。
CMS非常適合堆內存大,CPU核數多的服務器端應用,也是G1出現之前大型應用的首選收集器。
Concurrent Mark Sweep:并發標記清除,并發收集低停頓,并發指的是與用戶線程一起執行
開啟該收集器的JVM參數: -XX:+UseConcMarkSweepGC 開啟該參數后,會自動將 -XX:+UseParNewGC打開,開啟該參數后,使用ParNew(young 區用)+ CMS(Old 區用) + Serial Old 的收集器組合,Serial Old將作為CMS出錯的后備收集器
-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC
1
四個步驟
初始標記(CMS initial mark)
只是標記一個GC Roots 能直接關聯的對象,速度很快,仍然需要暫停所有的工作線程
并發標記(CMS concurrent mark)和用戶線程一起
進行GC Roots跟蹤過程,和用戶線程一起工作,不需要暫停工作線程。主要標記過程,標記全部對象
重新標記(CMS remark)
為了修正在并發標記期間,因用戶程序繼續運行而導致標記產生變動的那一部分對象的標記記錄,仍然需要暫停所有的工作線程,由于并發標記時,用戶線程依然運行,因此在正式清理前,在做修正
并發清除(CMS concurrent sweep)和用戶線程一起
清除GC Roots不可達對象,和用戶線程一起工作,不需要暫停工作線程?;跇擞浗Y果,直接清理對象,由于耗時最長的并發標記和并發清除過程中,垃圾收集線程可以和用戶現在一起并發工作,所以總體上來看CMS收集器的內存回收和用戶線程是一起并發地執行。
優點:并發收集低停頓
缺點:并發執行,對CPU資源壓力大,采用的標記清除算法會導致大量碎片
由于并發進行,CMS在收集與應用線程會同時增加對堆內存的占用,也就是說,CMS必須在老年代堆內存用盡之前完成垃圾回收,否則CMS回收失敗時,將觸發擔保機制,串行老年代收集器將會以STW方式進行一次GC,從而造成較大的停頓時間
標記清除算法無法整理空間碎片,老年代空間會隨著應用時長被逐步耗盡,最后將不得不通過擔保機制對堆內存進行壓縮,CMS也提供了參數 -XX:CMSFullGCSBeForeCompaction(默認0,即每次都進行內存整理)來指定多少次CMS收集之后,進行一次壓縮的Full GC
垃圾收集器如何選擇
組合的選擇
單CPU或者小內存,單機程序
-XX:+UseSerialGC
多CPU,需要最大的吞吐量,如后臺計算型應用
-XX:+UseParallelGC(這兩個相互激活)
-XX:+UseParallelOldGC
多CPU,追求低停頓時間,需要快速響應如互聯網應用
-XX:+UseConcMarkSweepGC
-XX:+ParNewGC
G1垃圾收集器
開啟G1垃圾收集器
-XX:+UseG1GC
1
以前收集器的特點
年輕代和老年代是各自獨立且連續的內存塊
年輕代收集使用單eden + S0 + S1 進行復制算法
老年代收集必須掃描珍整個老年代區域
都是以盡可能少而快速地執行GC為設計原則
G1是什么
G1:Garbage-First 收集器,是一款面向服務端應用的收集器,應用在多處理器和大容量內存環境中,在實現高吞吐量的同時,盡可能滿足垃圾收集暫停時間的要求。另外,它還具有一下特征:
像CMS收集器一樣,能與應用程序并發執行
整理空閑空間更快
需要更多的時間來預測GC停頓時間
不希望犧牲大量的吞吐量性能
不需要更大的Java Heap
G1收集器設計目標是取代CMS收集器,它同CMS相比,在以下方面表現的更出色
G1是一個有整理內存過程的垃圾收集器,不會產生很多內存碎片。
G1的Stop The World(STW)更可控,G1在停頓時間上添加了預測機制,用戶可以指定期望停頓時間。
CMS垃圾收集器雖然減少了暫停應用程序的運行時間,但是它還存在著內存碎片問題。于是,為了去除內存碎片問題,同時又保留CMS垃圾收集器低暫停時間的優點,JAVA7發布了一個新的垃圾收集器-G1垃圾收集器
G1是在2012奶奶才在JDK1.7中可用,Oracle官方計劃在JDK9中將G1變成默認的垃圾收集器以替代CMS,它是一款面向服務端應用的收集器,主要應用在多CPU和大內存服務器環境下,極大減少垃圾收集的停頓時間,全面提升服務器的性能,逐步替換Java8以前的CMS收集器
主要改變時:Eden,Survivor和Tenured等內存區域不再是連續了,而是變成一個個大小一樣的region,每個region從1M到32M不等。一個region有可能屬于Eden,Survivor或者Tenured內存區域。
特點
G1能充分利用多CPU,多核環境硬件優勢,盡量縮短STW
G1整體上采用標記-整理算法,局部是通過復制算法,不會產生內存碎片
宏觀上看G1之中不再區分年輕代和老年代。把內存劃分成多個獨立的子區域(Region),可以近似理解為一個圍棋的棋盤
G1收集器里面將整個內存區域都混合在一起了,但其本身依然在小范圍內要進行年輕代和老年代的區分,保留了新生代和老年代,但他們不再是物理隔離的,而是通過一部分Region的集合且不需要Region是連續的,也就是說依然會采取不同的GC方式來處理不同的區域
G1雖然也是分代收集器,但整個內存分區不存在物理上的年輕代和老年代的區別,也不需要完全獨立的Survivor(to space)堆做復制準備,G1只有邏輯上的分代概念,或者說每個分區都可能隨G1的運行在不同代之間前后切換。
底層原理
Region區域化垃圾收集器,化整為零,打破了原來新生區和老年區的壁壘,避免了全內存掃描,只需要按照區域來進行掃描即可。
區域化內存劃片Region,整體遍為了一些列不連續的內存區域,避免了全內存區的GC操作。
核心思想是將整個堆內存區域分成大小相同的子區域(Region),在JVM啟動時會自動設置子區域大小
在堆的使用上,G1并不要求對象的存儲一定是物理上連續的,只要邏輯上連續即可,每個分區也不會固定地為某個代服務,可以按需在年輕代和老年代之間切換。啟動時可以通過參數-XX:G1HeapRegionSize=n 可指定分區大?。?MB~32MB,且必須是2的冪),默認將整堆劃分為2048個分區。
大小范圍在1MB~32MB,最多能設置2048個區域,也即能夠支持的最大內存為:32MB*2048 = 64G內存
Region區域化垃圾收集器
Region區域化垃圾收集器
G1將新生代、老年代的物理空間劃分取消了
同時對內存進行了區域劃分
G1算法將堆劃分為若干個區域(Reign),它仍然屬于分代收集器,這些Region的一部分包含新生代,新生代的垃圾收集依然采用暫停所有應用線程的方式,將存活對象拷貝到老年代或者Survivor空間
這些Region的一部分包含老年代,G1收集器通過將對象從一個區域復制到另外一個區域,完成了清理工作。這就意味著,在正常的處理過程中,G1完成了堆的壓縮(至少是部分堆的壓縮),這樣也就不會有CMS內存碎片的問題存在了。
在G1中,還有一種特殊的區域,叫做Humongous(巨大的)區域,如果一個對象占用了空間超過了分區容量50%以上,G1收集器就認為這是一個巨型對象,這些巨型對象默認直接分配在老年代,但是如果他是一個短期存在的巨型對象,就會對垃圾收集器造成負面影響,為了解決這個問題,G1劃分了一個Humongous區,它用來專門存放巨型對象。如果一個H區裝不下一個巨型對象,那么G1會尋找連續的H區來存儲,為了能找到連續的H區,有時候不得不啟動Full GC。
回收步驟
針對Eden區進行收集,Eden區耗盡后會被觸發,主要是小區域收集 + 形成連續的內存塊,避免內碎片
Eden區的數據移動到Survivor區,加入出現Survivor區空間不夠,Eden區數據會晉升到Old區
Survivor區的數據移動到新的Survivor區,部分數據晉升到Old區
最后Eden區收拾干凈了,GC結束,用戶的應用程序繼續執行
回收完成后
小區域收集 + 形成連續的內存塊,最后在收集完成后,就會形成連續的內存空間,這樣就解決了內存碎片的問題
四步過程
初始標記:只標記GC Roots能直接關聯到的對象
并發標記:進行GC Roots Tracing(鏈路掃描)的過程
最終標記:修正并發標記期間,因為程序運行導致標記發生變化的那一部分對象
篩選回收:根據時間來進行價值最大化回收
參數配置
開發人員僅僅需要申明以下參數即可
三步歸納:-XX:+UseG1GC -Xmx32G -XX:MaxGCPauseMillis=100
-XX:MaxGCPauseMillis=n:最大GC停頓時間單位毫秒,這是個軟目標,JVM盡可能停頓小于這個時間
G1和CMS比較
G1不會產生內碎片
是可以精準控制停頓。該收集器是把整個堆(新生代、老年代)劃分成多個固定大小的區域,每次根據允許停頓的時間去收集垃圾最多的區域。
SpringBoot結合JVMGC
啟動微服務時候,就可以帶上JVM和GC的參數
IDEA開發完微服務工程
maven進行clean package
要求微服務啟動的時候,同時配置我們的JVM/GC的調優參數
我們就可以根據具體的業務配置我們啟動的JVM參數
例如:
java -Xms1024m -Xmx1024 -XX:UseG1GC -jar xxx.jar
1
參數配置
開發人員僅僅需要申明以下參數即可
三步歸納:-XX:+UseG1GC -Xmx32G -XX:MaxGCPauseMillis=100
-XX:MaxGCPauseMillis=n:最大GC停頓時間單位毫秒,這是個軟目標,JVM盡可能停頓小于這個時間
G1和CMS比較
G1不會產生內碎片
是可以精準控制停頓。該收集器是把整個堆(新生代、老年代)劃分成多個固定大小的區域,每次根據允許停頓的時間去收集垃圾最多的區域。
SpringBoot結合JVMGC
啟動微服務時候,就可以帶上JVM和GC的參數
IDEA開發完微服務工程
maven進行clean package
要求微服務啟動的時候,同時配置我們的JVM/GC的調優參數
我們就可以根據具體的業務配置我們啟動的JVM參數
例如:
java -Xms1024m -Xmx1024 -XX:UseG1GC -jar xxx.jar
1
總結
都看到這里了,關注一下唄
Java 任務調度
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。