如何在Java 9以上的JVM中微調G1垃圾回收? - DZone效能

banq發表於2019-04-26

垃圾回收器在執行某些垃圾回收任務時會暫停所有應用程式執行緒。這些暫停有時被稱為Stop-The-World暫停,因此儘可能避免這種情況是GC調優的主要目標,因為它們會對Java應用程式的效能產生巨大影響。

調整堆大小
垃圾回收調優的第一步是調整堆的大小。這是因為如果堆太小,則會發生太多的GC以回收記憶體,這會降低整體應用程式吞吐量,如果堆太大,那麼GC發生機率會少,一旦發生GC則需要很長時間,這樣你的應用的響應時間指標就會受到影響。並行收集器特別容易受到此問題的影響,因此如果您需要大堆並且暫停時間較短,那麼您應該嘗試使用G1GC收集器。

旁註:因為Java 9和Shenandoah垃圾收集器在撰寫本文時仍被視為“實驗性”時,不推薦使用併發標記掃描(CMS)收集器。因此,如果您正在執行線上互動式應用程式,那麼G1GC應該是您的預設選擇,如果您正在執行離線批處理應用程式,那麼並行收集器應該是您的首選。

堆的大小由兩個值控制:使用ms標誌指定的初始值和使用mx標誌指定的最大值。

-Xms1g -Xmx8g


堆的初始和最大大小允許JVM根據工作負載自動調整堆大小。如果JVM遇到記憶體壓力並且觀察到GC執行過多,它會不斷增加堆,直到記憶體壓力消失,或直到堆達到其最大大小。如果記憶體壓力很低,JVM還可以透過縮小堆大小來決定減少暫停時間。這個過程稱為自適應大小調整,它不僅可以調整堆的整體大小,還可以調整年輕代和老代的大小和比例。
如果您花時間精細調整應用程式的GC行為和大小,則可以選擇關閉自適應大小調整。這可以節省JVM計算堆大小所需的一小段時間。您可以透過將標誌設定UseAdaptiveSizePolicy為false 來執行此操作。

-XX:-UseAdaptiveSizePolicy


此外,將初始堆大小設定為與最大堆大小相同的值或將初始新gen大小設定為與最大新gen大小相同的值只能關閉大小自適應調整行為的一部分。
強烈建議的設定最大堆大小的準則是最大堆大小不應超過計算機上的實體記憶體量。如果您執行多個JVM,則最大堆大小的總和不應超過計算機的實體記憶體。
設定最大堆大小的更一般建議是:在完整GC之後堆佔用大約30%,要計算此值,您可以在GC日誌中查詢完整GC發生的條目,並觀察GC完成時使用的記憶體量。或者,您可以執行應用程式,直到它達到穩定狀態,然後使用jconsole或強制使用完整的GC jcmd。

調整GC效能
如果啟用了自適應大小調整,則可以使用MaxGCPauseMillis標誌來調整GC行為,此標誌設定最大GC暫停時間的目標,當與Parallel收集器一起使用時,JVM將調整年輕一代和老一代的大小,以便嘗試達到目標,然後它將調整堆的大小,以便在GC中花費的時間不超過某個值,預設情況下為1%。
G1GC的目標之一是它只需要很少的調整,因此,在G1GC中,一個調整引數MaxGCPauseMillis執行以下所有最佳化,以嘗試實現指定的暫停時間目標:

  • 調整堆的大小
  • 更快開始後臺處理,
  • 調整閾值:物件成為老生代的物件的時間期限,
  • 調整在混合GC迴圈期間處理的舊區域數。

在G1GC中,標誌的預設值為200 ms。雖然你可能想把它設定成一個非常小的20毫秒,但請注意,為了達到這個目的,垃圾收集器會將年輕一代收縮到一個非常小的尺寸並收集較少的老一代,這最終會導致老一代垃圾過多的情況,系統必須執行完整的GC,這是不可取的。

修復併發模式故障
G1GC是一個併發收集器,這意味著當應用程式執行緒仍在執行時,垃圾收集程式的某些階段可以併發執行,並且由於正在執行的應用程式可以繼續產生垃圾,我們可能會遇到應用程式耗盡老生代記憶體而垃圾收集器仍在垃圾收集過程中的情況。換句話說,正在執行的應用程式生成的垃圾比它可以清理的速度快。這種情況稱為併發模式故障、失效故障或疏散故障,具體取決於故障發生的時間。如果您在GC日誌中看到很多這些錯誤,解決方案是增加堆的大小,更早地啟動G1後臺處理,或者透過使用更多後臺執行緒來加速GC處理。

要更頻繁地執行G1後臺活動,您可以降低觸發G1迴圈的閾值。這是透過減少InitiatingHeapOccupancyPercent標誌的值來實現的。

-XX:InitiatingHeapOccupancyPercent=45


預設情況下,此標誌設定為45。這意味著當堆填充45%時會觸發GC迴圈。減少此值意味著GC會更早且更頻繁地觸發。但應注意的是,該值不會設定為太低而導致GC過於頻繁發生。

要增加後臺執行緒數,請使用該ConcGCThreads標誌。

-XX:ConcGCThreads=4


此標誌的預設值設定為ParallelGCThreadss加2除以4.只要計算機上有足夠的CPU可用,就可以增加此值而不會導致任何效能損失。
如果調整堆大小並調整收集器對您不起作用,那麼您可以嘗試另一個收集器。如果你仍然沒有取得好成績,那麼你需要考慮調整應用程式程式碼本身。

相關文章