Java 效能調優:最佳化 GC 執行緒設定

公众号-JavaEdge發表於2024-09-17

垃圾回收器使用一組稱為 GC 執行緒的執行緒來執行回收工作。有時 JVM 可能會分配過多或過少的 GC 執行緒。本文將討論 JVM 為什麼會出現這種情況、其影響以及可能的解決方案。

1 咋查詢應用程式的 GC 執行緒數量

進行執行緒轉儲分析來確定應用程式的 GC 執行緒數量:

  1. 從生產伺服器捕獲thread dump
  2. 使用thread dump分析工具進行分析
  3. 立即顯示 GC 執行緒數量,如圖

還可透過 JMX(Java Management Extensions)或VisualVM、JConsole 等檢視 GC 執行緒數量。

2 咋設定 GC 執行緒數量?

JVM 引數手動調整 GC 執行緒數:

  • -XX:ParallelGCThreads=n:設定垃圾回收器並行階段使用的執行緒數量
  • -XX:ConcGCThreads=n:控制垃圾回收器併發階段使用的執行緒數量

注意這些引數適用於並行垃圾回收器(如 ParallelGC 和 ParallelOldGC)和併發垃圾回收器(如 G1GC)。

3 預設 GC 執行緒數量多少?

根據伺服器或容器中的 CPU 數量自動計算。

  • -XX:ParallelGCThreads 預設值:在 Linux/x86 系統上,預設值公式:
if (處理器數量 <=8) {   
   返回處理器數量; 
} else {  
  返回 8 + (處理器數量 - 8) * (5/8); 
}

因此,如果 JVM 執行在擁有 32 個處理器的伺服器上,那麼 ParallelGCThread 的值將是 23。

  • -XX:ConcGCThreads 預設值:公式:
max((ParallelGCThreads+2)/4, 1)

因此,如果 JVM 執行在 32 個處理器的伺服器上:

  • ParallelGCThread 的值將是 23(即 8 + (32 – 8) * (5/8))
  • ConcGCThreads 的值將是 6(即 max(25/4, 1))

4 JVM 會分配過多的 GC 執行緒嗎?

JVM 可能在你不知情下分配過多 GC 執行緒。因為預設 GC 執行緒數量是根據伺服器或容器中的 CPU 數量自動確定。

如在擁有 128 個 CPU 機器,JVM 可能會為垃圾回收的並行階段分配大約 80 個執行緒,併為併發階段分配大約 20 個執行緒,總計 100 個 GC 執行緒。

如你在這臺 128 CPU 的機器上執行多個 JVM,每個 JVM 可能會分配大約 100 個 GC 執行緒。這會導致資源的過度使用,因為所有這些執行緒都在爭奪相同的 CPU 資源。這種情況在容器化環境中特別常見,因為多個應用程式共享相同的 CPU 核心,導致 JVM 分配的 GC 執行緒超過所需數量,從而降低整體效能。

容器化環境

JVM 可能根據容器分配的 CPU 資源來計算 GC 執行緒數量,而非物理機器的 CPU 數量。這可能導致在共享 CPU 資源的容器環境中分配過多的 GC 執行緒。

5 過多GC執行緒也是問題?

雖然 GC 執行緒對高效的記憶體管理非常重要,但過多 GC 執行緒可能會導致 Java 應用程式效能問題。

上下文切換增加

當 GC 執行緒過多時,作業系統需要頻繁地在這些執行緒之間切換,導致上下文切換的開銷增加,更多的 CPU 時間花在管理執行緒上,而不是執行應用程式程式碼,結果應用程式可能會明顯變慢。

CPU 開銷增加

每個 GC 執行緒都會消耗 CPU 資源,過多的執行緒同時活躍時,它們會爭奪 CPU 時間,減少應用程式的主要任務的處理能力,特別是在 CPU 資源有限的情況下。

記憶體爭用

過多的 GC 執行緒會增加記憶體資源爭用,多個執行緒同時訪問和修改記憶體會導致鎖爭用,從而進一步降低應用程式效能。

GC 暫停時間增加,吞吐量下降

過多的 GC 執行緒會使垃圾回收過程低效,導致更長的 GC 暫停時間,應用程式會被暫時中斷,延長的暫停時間可能會造成明顯的延遲或卡頓。此外,更多的時間花在垃圾回收上而不是處理請求,應用程式的整體吞吐量會下降,從而影響其在高負載下的擴充套件性和效能。

延遲增加

由於過多執行緒導致 GC 活動增加,響應使用者請求或處理任務的延遲也會增加,這對需要低延遲的應用程式來說尤其嚴重,例如實時系統或高頻交易平臺。

邊際效益遞減

增加 GC 執行緒到一定程度後,並不會繼續提高效能,反而會出現邊際效益遞減,管理這些執行緒的開銷超過了更快垃圾回收的好處,這會導致應用效能下降。

6 過少GC執行緒還是問題?

過少的 GC 執行緒同樣會給 Java 應用程式帶來問題。原因如下:

  1. 垃圾回收時間延長:GC 執行緒過少時,垃圾回收所需時間變長,執行緒少,處理時間長,GC 暫停時間也隨之延長。
  2. 應用程式延遲增加:垃圾回收時間過長會增加應用程式的延遲,特別是對於需要低延遲的應用程式,使用者可能會感到應用程式無響應。
  3. 吞吐量降低:GC 執行緒數量不足會導致垃圾回收器工作效率降低,進而影響整體吞吐量,應用程式每秒處理的請求或事務變少,影響其擴充套件能力。
  4. CPU 利用率低下:執行緒過少時,CPU 核心可能無法充分利用,部分核心閒置,部分核心負載過重,資源利用率不均衡。
  5. 增加OOM和記憶體洩漏風險:GC 執行緒過少可能導致垃圾回收器無法跟上記憶體分配的速度,回收不及時,可能出現OOM,甚至導致記憶體洩漏和崩潰。

7 最佳化 GC 執行緒數的解決方案

若應用程式因 GC 執行緒數量不當導致效能問題,可透過 JVM 引數手動調整 GC 執行緒數:

  • -XX:ParallelGCThreads=n
  • -XX:ConcGCThreads=n

在生產環境中應用這些更改前,先研究應用程式的 GC 行為,收集並分析 GC 日誌。根據分析結果,判斷當前執行緒設定是否導致效能瓶頸,然後進行相應調整。

務必在受控環境中測試這些更改,以確保它們的確能改善效能,然後再應用於生產環境。調整 GC 執行緒數量時,應結合應用程式的實際工作負載、記憶體使用情況和硬體配置進行綜合考慮。此外,可以使用工具如 GCViewer 來分析 GC 日誌,以更好地理解 GC 行為並進行最佳化。

8 總結

平衡 GC 執行緒數量對 Java 應用程式的平穩執行至關重要。透過仔細監控和調整這些設定,可以避免潛在的效能問題,並保持應用程式的高效執行。

關注我,緊跟本系列專欄文章,咱們下篇再續!

作者簡介:魔都架構師,多家大廠後端一線研發經驗,在分散式系統設計、資料平臺架構和AI應用開發等領域都有豐富實踐經驗。

各大技術社群頭部專家博主。具有豐富的引領團隊經驗,深厚業務架構和解決方案的積累。

負責:

  • 中央/分銷預訂系統效能最佳化
  • 活動&券等營銷中臺建設
  • 交易平臺及資料中臺等架構和開發設計
  • 車聯網核心平臺-物聯網連線平臺、大資料平臺架構設計及最佳化
  • LLM Agent應用開發
  • 區塊鏈應用開發
  • 大資料開發挖掘經驗
  • 推薦系統專案

目前主攻市級軟體專案設計、構建服務全社會的應用系統。

參考:

  • 程式設計嚴選網

本文由部落格一文多發平臺 OpenWrite 釋出!

相關文章