JVM系列,還不會選擇合適的垃圾收集器?

Java是流行多年的編程語言,深受廣大小夥伴的歡迎,其主要有兩個特點:

  • 跨平臺:write once run anywhere,一次編寫,到處運行。這裡的一次編寫指的是從.java文件被編譯成.class文件的過程。到處運行:是指安裝了JVM的不同操作系統(平臺),c.lass文件就可以在該平臺上進行運行了,有JVM負責解釋或者編譯執行字節碼。
  • 垃圾回收:程序員不用再像使用C或者C++開發時候關心內存的分配和釋放了,內存的管理是有垃圾回收器來管理的,減少了內存洩漏的概率。垃圾回收器由JVM的後臺線程實現垃圾對象的回收。

垃圾收集器

JVM中的垃圾收集器一直在不斷髮展中,比較成熟的垃圾回收器有串行回收器、並行回收器、標記回收器、垃圾優先回收器等,JDK11中引入了ZGC,JDK12中引入另外一款垃圾回收器Shenandoah。

雖然垃圾回收器在不斷更新,但是垃圾收集算法基本沒變:

複製、標記清除、標記壓縮。

不同的垃圾收集器都是基於上面這些基本方法實現的,不同垃圾收集器的區別在於亮點:

  1. 使用的算法不一樣
  2. 實現是後臺線程採用的並行/併發方式不一樣

本文主要來聊下面幾種垃圾回收器的特性及如何選擇

JVM系列,還不會選擇合適的垃圾收集器?


參考:JVM的7種垃圾收集器的特點及使用場景

JVM系列,還不會選擇合適的垃圾收集器?


G1收集器

G1 的全稱是 Garbage-First,意為垃圾優先,哪一塊的垃圾最多就優先清理它。

G1 GC 最主要的設計目標是:將STW(stop the world) 停頓的時間和分佈,變成可預期且可配置的。

事實上,G1 GC 是一款軟實時垃圾收集器,可以為其設置某項特定的性能指標。例如可以指定:在任意 xx 毫秒時間範圍內,STW停頓不得超過 yy 毫秒。舉例說明:任意 1 秒內暫停時間不超過 5 毫秒。G1 GC 會盡力達成這個目標(有很大概率會滿足,但並不完全確定)。

JDK 7開始使用,JDK8非常成熟,JD 9默認的垃圾收集器,適用於新老生代。

G1致力於在多CPU和大內存服務器上對垃圾回收提供軟實時目標(soft real -time goal)和高吞吐量(high throuhput)。

判斷是否需要使用G1收集器?

  1. 50%以上的堆被存活對象佔用
  2. 對象分配和晉升的速度變化非常大
  3. 垃圾回收時間比較長

ZGC收集器

ZGC(Z Garbage Collector)作為一種比較新的收集器,目前還沒有得到大範圍的關注。作為一款低延遲的垃圾收集器,它有如下幾個亮點:

•停頓時間不會超過 10ms

•停頓時間不會隨著堆的增大而增大(控制停頓時間在10ms內)

•支持堆的大小範圍很廣(8MB-16TB)

在ZGC中,連邏輯上的也是重新定義了堆空間(不區分年輕代和老年代),只分為一塊塊的page,每次進行GC時,都會對page進行壓縮操作,所以沒有碎片問題。雖然ZGC屬於很新的GC技術, 但優點不一定真的出眾,ZGC只在特定情況下具有絕對的優勢, 如巨大的堆和極低的暫停需求。而實際上大多數開發在這兩方面都不太成問題(尤其是在服務器端), 而對GC的性能/效率更在意。也有一種觀點認為ZGC是為大內存、多cpu而生,它通過分區的思路來降低STW。

垃圾收集器分類

  • 串行收集器--->Serial和Serial Old,只能有一個垃圾回收線程執行,用戶線程暫停。
  • 適用於內存比較小的嵌入式設備 。
  • 並行收集器[吞吐量優先]--->Parallel Scanvenge、Parallel Old,多條垃圾收集線程並行工作,但此時用戶線程仍然處於等待狀態。
  • 適用於科學計算、後臺處理等若交互場景 。
  • 併發收集器[停頓時間優先]--->CMS、G1,用戶線程和垃圾收集線程同時執行(但並不一定是並行的,可能是交替執行的),垃圾收集線程在執行的時候不會停頓用戶線程的運行。
  • 適用於相對時間有要求的場景,比如 Web 。

如何理解理解吞吐量和停頓時間

  • 停頓時間->垃圾收集器 進行 垃圾回收終端應用執行響應的時間
  • 吞吐量->運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間)

停頓時間越短就越適合需要和用戶交互的程序,良好的響應速度能提升用戶體驗;

高吞吐量則可以高效地利用CPU時間,儘快完成程序的運算任務,主要適合在後臺運算而不需要太多交互的任務。

小結:這兩個指標也是評價垃圾回收器好處的標準,其實調優也就是在觀察者兩個變量。

如何選擇合適的垃圾收集器

  • 優先調整堆的大小讓服務器自己來選擇
  • 如果內存小於100M,使用串行收集器
  • 如果是單核,並且沒有停頓時間要求,使用串行或JVM自己選
  • 如果允許停頓時間超過1秒,選擇並行或JVM自己選
  • 如果響應時間最重要,並且不能超過1秒,使用併發收集器

如何開啟需要的垃圾收集器

  • 串行
  • -XX:+UseSerialGC
  • -XX:+UseSerialOldGC
  • 並行(吞吐量優先):
  • -XX:+UseParallelGC
  • -XX:+UseParallelOldGC
  • 併發收集器(響應時間優先)
  • -XX:+UseConcMarkSweepGC
  • -XX:+UseG1GC



分享到:


相關文章: