上一篇JVM專題十:JVM中的垃圾回收機制專題中,我們主要介紹了Java的垃圾機制,包括垃圾回收基本概念,重點介紹了垃圾回收機制中自動內存管理與垃圾收集算法。如果說收集算法是內存回收的方法論,那么垃圾收集器就是內存回收的具體實現。本章節就讓我具體的垃圾回收器以及他們各自的優缺點,由于垃圾回收器內容比較多,本專題主要討論分代收集器如:Parallel、ParNew、CMS等,關于G1、ZGC等放到專題十二
簡介
如上圖所示JVM 的垃圾收集器主要分為兩大類:分代收集器和分區收集器,分代收集器的代表是 CMS,分區收集器的代表是 G1 和 ZGC,下面我們來看看各個收集器之間的聯系與版本。
Java虛擬機(JVM)中不同版本的垃圾收集器(GC)及其引入的Java Development Kit(JDK)版本的概述。以下是對這些核心內容的整理:
新生代收集器:
- Serial GC:單線程收集器,適用于JDK 1.3及之前版本,以及小數據量的內存管理。
- ParNew GC:Serial GC的多線程版本,適用于JDK 1.4及之后版本。
- Parallel GC:吞吐量優先的多線程收集器,適用于JDK 1.4及之后版本。
- Epsilon GC:無操作的收集器,用于測試,從JDK 11開始引入。
收集算法:
- Scavenge:新生代的復制算法,用于Serial和ParNew GC。
- Copying:復制算法,用于新生代對象的收集。
老年代收集器:
- Serial Old GC:Serial GC的老年代版本,使用標記-整理算法。
- Parallel Old GC:Parallel GC的老年代版本,使用多線程標記-整理算法。
- CMS (Concurrent Mark Sweep) GC:并發標記清除算法,減少停頓時間,從JDK 1.5開始引入。
- MarkCompact:標記-整理算法,用于CMS和Parallel Old GC。
其他收集器:
- G1 (Garbage-First) GC:從JDK 1.7開始引入,適用于大堆內存。
- ZGC:可擴展、低延遲的收集器,從JDK 11開始引入。
- Shenandoah GC:并發低延遲收集器,從JDK 9開始引入(默認)。
收集器的引入時間線:
- JDK 1.3:引入Serial Old GC和整體的標記-整理(MSC)算法。
- JDK 1.4:引入Serial、ParNew、Parallel GC,以及新生代的Scavenge算法。
- JDK 1.5:引入CMS GC。
- JDK 1.6:引入Parallel Old GC。
- JDK 1.7:引入G1 GC。
- JDK 9:引入Shenandoah GC,并且CMS成為默認的收集器。
- JDK 11:引入ZGC和Epsilon GC。
上圖提供了JVM垃圾收集器隨JDK版本演進的概覽,展示了不同收集器的特點和它們被引入的時間點。開發者可以根據這些信息,結合自己的應用需求和JDK版本,選擇合適的垃圾收集器。
分代收集器
Serial收集器
Serial收集器是Java虛擬機(JVM)中一個非常基礎的垃圾收集器,它在JDK 1.3之前是默認的收集器。以下是關于Serial收集器的一些核心信息:
-
單線程操作:Serial收集器在進行垃圾收集時使用單個線程,這意味著在收集過程中,它不會利用多核處理器的優勢。
-
Stop The World:在Serial收集器進行垃圾收集期間,所有的應用線程會被暫停,直到收集完成。這種停頓被稱為"Stop The World",可能會對應用程序性能產生影響,尤其是在垃圾收集周期較長時。
-
新生代收集:Serial收集器在新生代使用復制(Copying)算法,這是一種簡單且高效的算法,適用于新生代,因為新生代中的對象大多是朝生夕死。
-
老年代收集:Serial Old收集器是Serial收集器的老年代版本,對于老年代,Serial收集器使用標記-整理(Mark-Compact)算法。這種算法首先標記存活的對象,然后整理內存,使得所有存活的對象都移動到內存的一端,從而避免內存碎片。它同樣是一個單線程收集器。它主要有兩大用途:一種用途是在JDK1.5以及以前的版本中與Parallel Scavenge收集器搭配使用,另一種用途是作為CMS收集器的后備方案。
-
適用場景:Serial收集器主要適用于單核處理器或者小型應用,以及對延遲不敏感的場景。
-
配置選項:可以通過JVM參數?
-XX:+UseSerialGC?
來指定使用Serial收集器進行新生代收集,通過?-XX:+UseSerialOldGC?
來指定使用Serial Old收集器進行老年代收集。 -
性能特點:雖然Serial收集器在現代多核處理器上可能不是最高效的選擇,但它的簡單性和低資源消耗使其在某些特定場景下仍然有用。
-
與其他收集器的比較:與并行或并發收集器相比,Serial收集器在多核處理器上的性能可能較差,但在單核系統或資源受限的環境中,它可能是一個合適的選擇。
總的來說,Serial收集器是一個簡單且歷史悠久的垃圾收集器,雖然在現代應用中可能不是首選,但在特定的低資源環境中,它仍然有其用武之地。隨著JVM的發展,更多的高級收集器被引入,以滿足不同應用場景的需求。
Parallel收集器
Parallel收集器其實就是Serial收集器的多線程版本,除了使用多線程進行垃圾收集外,其余行為控制參數、收集算法、回收策略等等和Serial收集器類似。關于Parallel收集器及其變體的核心信息概述如下:
- Parallel收集器:
- 多線程:使用多個線程進行垃圾收集。
- 線程數配置:默認線程數與CPU核心數相同,可通過
-XX:ParallelGCThreads
指定。 - 吞吐量優先:專注于高效率利用CPU。
- 參數調節:提供參數以調整停頓時間或吞吐量。
- Parallel Old收集器:
- Parallel 老年代版本:使用多線程和標記-整理算法。
- 收集算法:
- 新生代:復制算法。
- 老年代:標記-整理算法。
- JDK默認設置:
- JDK 8:默認使用Parallel Scavenge和Parallel Old。
這些收集器適用于需要高吞吐量的應用,尤其是在多核處理器環境中,通過參數配置可以實現高效的垃圾收集。
ParNew收集器
ParNew收集器作為Serial收集器的多線程版本,與Parallel收集器在很多方面相似,但它們之間存在一些關鍵的差異和特定的使用場景。以下是ParNew收集器的核心信息:
-
多線程支持:ParNew收集器使用多個線程進行垃圾收集,與Parallel收集器類似,可以充分利用多核處理器的優勢。
-
與CMS的兼容性:ParNew收集器的主要特點是它可以與CMS(Concurrent Mark Sweep)收集器配合使用。CMS是一種并發收集器,主要關注減少垃圾收集期間的用戶線程停頓時間。
-
新生代收集:ParNew收集器在新生代使用復制算法,這是一種簡單且高效的算法,適用于新生代,因為新生代中的對象大多是朝生夕死。
-
Server模式下的默認選擇:在Server模式下,ParNew收集器通常是首選,特別是當應用需要與CMS收集器配合工作時。
-
適用場景:ParNew收集器適用于需要快速響應垃圾收集需求的多核服務器環境,尤其是在與CMS收集器結合使用時,可以提供較低的停頓時間。
-
配置選項:可以通過JVM參數
-XX:+UseParNewGC
來指定使用ParNew收集器進行新生代收集。
ParNew收集器的優勢在于它能夠與CMS收集器協同工作,提供一種平衡吞吐量和停頓時間的解決方案。這種組合特別適合那些需要高吞吐量同時又希望減少垃圾收集引起的停頓的應用場景。然而,開發者需要根據具體的應用需求和性能目標來決定是否使用ParNew與CMS的組合,或者選擇其他的垃圾收集器配置。
CMS收集器
CMS(Concurrent Mark Sweep)收集器是一種以減少垃圾收集(GC)過程中的停頓時間為目標的垃圾收集策略。以下是CMS收集器的詳細概述,包括其優點和缺點:
CMS收集器概述:
- 目標:最小化GC引起的停頓時間,提高用戶體驗。
- 并發性:HotSpot虛擬機中第一款實現垃圾收集線程與用戶線程并發工作的收集器。
運作過程:
- 初始標記:短暫停頓(STW),記錄GC Roots直接引用的對象。
- 并發標記:遍歷對象圖,耗時但用戶線程不停頓,與GC線程并發運行。
- 重新標記:修正并發標記期間由于用戶程序運行導致的標記變動,使用增量更新算法。
- 并發清理:用戶線程開啟,GC線程清掃未標記區域,新增對象被標記為黑色。
- 并發重置:重置GC過程中的標記數據。
CMS收集器優點:
- 并發收集:減少GC引起的停頓時間。
- 低停頓:特別適合注重響應時間的應用。
CMS收集器缺點:
- CPU資源敏感:GC線程與用戶線程競爭CPU資源。
- 浮動垃圾問題:并發標記和清理階段產生的垃圾需等到下一次GC處理。
- 空間碎片:使用“標記-清除”算法可能導致空間碎片,可通過參數-XX:+UseCMSCompactAtFullCollection進行整理。
- 不確定性:可能發生“concurrent mode failure”,即上一次GC未完成就觸發新的GC,此時會使用Serial Old收集器進行回收。
其他注意事項:
- 參數調整:合理配置JVM參數可以優化CMS收集器的性能。
- 適用場景:適用于對響應時間要求較高的應用,如Web服務器。
CMS收集器的設計目標是減少GC引起的停頓時間,通過并發執行大部分GC工作來實現這一目標。然而,它也有一些局限性,如對CPU資源的敏感性、浮動垃圾問題和空間碎片問題。開發者需要根據應用的具體需求和運行環境來決定是否使用CMS收集器,并進行適當的參數調整以優化性能。
CMS(Concurrent Mark Sweep)收集器的一些核心參數,它們可以用于調整和優化CMS收集器的行為:
-XX:+UseConcMarkSweepGC
:啟用CMS垃圾收集器。
-XX:ConcGCThreads
:設置并發GC線程的數量,即在并發標記和并發清理階段使用的線程數。
-XX:+UseCMSCompactAtFullCollection
:在Full GC之后執行內存壓縮整理,以減少內存碎片。
-XX:CMSFullGCsBeforeCompaction
:設置在多少次Full GC之后執行一次壓縮整理,默認值為0,意味著每次Full GC后都會進行壓縮整理。
-XX:CMSInitiatingOccupancyFraction
:設置老年代占用達到該比例時觸發Full GC的閾值,默認為92%。
-XX:+UseCMSInitiatingOccupancyOnly
:僅使用-XX:CMSInitiatingOccupancyFraction
設置的回收閾值。如果不設置此參數,JVM在第一次使用設定值后,后續會根據實際情況自動調整閾值。
-XX:+CMSScavengeBeforeRemark
:在CMS GC的重新標記階段前啟動一次Minor GC,減少標記階段的開銷。由于CMS GC的大部分耗時通常在標記階段,此參數可以提高效率。
-XX:+CMSParallellnitialMarkEnabled
:在初始標記階段使用多線程執行,以縮短停頓時間。
-XX:+CMSParallelRemarkEnabled
:在重新標記階段使用多線程執行,進一步縮短停頓時間。
通過調整這些參數,開發者可以根據應用的具體需求和運行環境來優化CMS收集器的性能。例如,如果應用對停頓時間非常敏感,可以增加并發GC線程數或調整觸發Full GC的閾值。如果內存碎片是一個問題,可以啟用內存壓縮整理。這些參數提供了靈活性,使得CMS收集器可以適應不同的應用場景。
三色標記
三色標記算法是現代垃圾收集器中用于解決并發標記問題的一種算法。以下是三色標記算法的詳細解釋:
三色標記算法概述:
- 黑色對象:已被垃圾收集器訪問,并且從該對象出發的所有引用都已掃描。黑色對象是安全的,不會指向任何未被訪問的白色對象,即它們不會導致漏標。
- 灰色對象:已被垃圾收集器訪問,但從該對象出發的至少有一個引用尚未被掃描。灰色對象作為工作列表的一部分,將被進一步探索。
- 白色對象:尚未被垃圾收集器訪問。在分析開始時,所有對象都是白色的。如果分析結束時對象仍然是白色的,那么它們是不可達的,即可以被回收的垃圾對象。
算法步驟:
- 從GC Roots開始,將所有直接可達的對象標記為灰色,并加入工作列表。
- 從工作列表中取出灰色對象,掃描它的所有引用,將新發現的未訪問對象(白色對象)標記為灰色,并加入工作列表。
- 重復步驟2,直到工作列表為空,此時所有可達的對象都已被訪問并標記為黑色或灰色。
- 如果在并發標記期間對象的引用發生了變化,增量更新算法會修正這些變化,確保不會漏標。
優點:
- 減少停頓時間:三色標記算法允許垃圾收集器在標記階段與應用程序并發運行,減少停頓時間。
缺點:
- 處理并發變動:在并發標記期間,如果對象的引用發生變化,需要特殊處理以避免漏標。
應用:
- 三色標記算法廣泛應用于并發垃圾收集器中,如CMS收集器的并發標記階段。
增量更新:
- 在并發標記期間,如果應用程序繼續運行,對象的引用可能發生變化。增量更新算法用于處理這些變化,確保標記的準確性。
三色標記算法通過區分已訪問和未訪問的對象,有效地避免了在并發標記期間由于對象引用變化導致的漏標問題。這種算法是實現低延遲垃圾收集的關鍵技術之一。
小節
其實章節最最主要的還是要掌握CMS相關知識掉。目前用的最多的就是他了,同時你們也可以看下自己產線用的是什么收集器。和相關參數怎么配置的,為什么這么配置根據是什么。