快速上手jvm調優:GC調優思路及參數設置

本文基於《jvm性能權威指南》,總結了gc調優的相關知識點。然後希望能幫助大家快速上手jvm gc調優。
這裏不對垃圾收集的原理進行詳細介紹,只與性能調優相關。

一、垃圾收集器

1.各垃圾收集器主要特點
垃圾收集器 主要特點 啓用參數
Serial垃圾收集器 Client模式默認垃圾收集器;
單線程回收;
MinorGC和FullGC都會暫停應用線程。
-XX:+UseSerialGC
Parallel垃圾收集器 Server模式默認垃圾收集器(jdk9前);
使用多線程回收;
MinorGC和FullGC都會暫停應用線程,FullGC會對老年代空間進行壓縮整理。
-XX:+UseParallelGC,
-XX:+UseParallelOldGC
CMS垃圾收集器 使用多線程回收;
MinorGC和老年代併發回收階段暫停應用線程,會有空間碎片化問題。
-XX:+UseParNewGC,
-XX:+UseConcMarkSweepGC
G1垃圾收集器 jdk9後默認垃圾收集器;
使用非連續的區塊的方式管理堆內存;
多線程並行回收;
MinorGC和老年代併發回收部分階段暫停應用線程。
-XX:+UseG1GC
2.如何選擇垃圾收集器
  • 小內存應用直接使用Serial,穩定高效
  • 大部分應用在Parallel和CMS中選擇:
    • Parallel+Parallel old組合主要關注吞吐量,適用批處理任務
    • 在CPU資源充足的情況下使用CMS(CMS只使用老年代,需要配合serial/parallel new)
    • CPU資源受限時CMS會發生併發模式失效的問題,退化到Serial Old
  • 一般情況下,堆空間小於4G時,CMS比G1性能好,但超大堆下G1性能更好

二、GC調優基礎

1.分析工具

所有調優都是建立在對堆內存的使用情況有一定的瞭解的基礎上,所以我們首先需要使用一些工具對我們的java應用進行監控和分析,來瞭解到底出現了什麼問題:

  • GC日誌
    • -XX:+PrintGCDetails:打印GC日誌
    • -XX:+PrintGCTimeStamps:GC日誌打印時間戳
  • 堆實時監控
    • 使用jstat -gcutil PID 1000 指令:每秒打印堆內存實時信息及GC情況
2.調整堆大小
  • 考慮維度:
    • GC頻率:過頻繁時需要增大堆大小
    • 單次GC耗時:耗時過長需要考慮控制堆大小
    • GC在整個時間中所佔百分比
    • FullGC後剩餘可用空間:普遍經驗爲70%可用
    • 調優參數:
      • -Xms=N、-Xmx=N:堆初始值和最大值
      • -Xmn=N:設置固定新生代大小
      • -XX:NewRatio=N:設置新生代與老年代空間佔用比(此值爲分母)
      • -XX:NewSize=N、-XX:MaxNewSize=N:設置新生代初始和最大值
3.永久代和元空間
  • 元空間默認會使用儘可能多的空間,因此不用過於關注
  • 永久代(jdk7及之前)
    • -XX:PermSize=N、-XXMaxPermSize=N:設置固定永久代大小和最大值
  • 元空間(jdk8以後)
    • -XX:MetaspaceSize=N、-XX:MaxMetaspaceSize=N:設置固定元空間大小和最大值
4.控制併發
  • 控制線程數:-XX:ParallelGCThreads=N,影響多線程操作:
    • Parallel 收集新生代和老年代
    • CMS:新生代收集(ParNewGC)、併發收集STW階段(非FullGC)
    • G1 新生代收集、STW階段(非FullGC)
  • 默認線程數計算(n爲cpu線程數):ParallelGCThreads = 8 + ( ( N-8 ) * 5 / 8 )
    • 當機器CPU線程數比較多,此時默認線程數會比較大,而又同時運行多個jvm實例,這時需要手動控制線程數,避免過多垃圾回收線程併發運行。
5.自適應調整

JVM會自己根據以往的性能歷史進行性能參數調整

  • -XX:-UseAdaptiveSizePolicy:關閉自適應調整功能(默認開啓)
  • -XX:+PrintAdaptiveSizePolicy:打印自動調整信息

三、進階調優

1. Parallel GC
  • Parallel收集器會根據指標自適應調整堆大小
    • -XX:MaxGCPauseMillis=N:設置最大停頓時間
      • 傾向於降低老年代大小,可能會觸發頻繁FullGC
    • -XX:GCTimeRatio=N:設置應用線程運行時間與垃圾回收時間之比(默認99)
      • N = 應用時間佔比 / (1 - 應用時間佔比 )
      • N=99時,表示GC佔總時間1%
      • 傾向於增大堆大小
2. CMS
  • 退化爲FullGC的情況:
    • 併發模式失效:新生代發生垃圾回收,而老年代沒有足夠空間容納晉升對象
    • 晉升失敗:老年代有足夠空間容納晉升對象,但是由於空間碎片化導致晉升失敗
    • 永久代空間用盡
  • 控制併發週期啓動時機
    • -XX:+UseCMSInitiatingOccupancyOnly:不自動調整CMS垃圾收集週期(默認false)
    • -XX:CMSInitiationOccupancyFraction=N:觸發併發收集週期的老年代空間佔用比閾值(默認70)
      • 不要將閾值設置得過低,至少要比堆內活躍數據數多10%~20%,頻繁的併發週期中的STW會導致總體停頓過多
  • 調整CMS後臺線程
    • -XX:ConcGCThreads=N:後臺線程數目
      • 默認根據ParallelGCThreads值計算得來:N = ( 3 + ParallelGCThreads ) / 4
3. G1
  • 退化爲FullGC的情況:
    • 併發模式失效:(參考cms)
    • 晉升失敗:(參考cms)
    • 疏散失敗:進行新生代垃圾收集時,Suvivor空間和老年代空間沒有足夠空間容納倖存對象
    • 巨型對象分配失敗:對象所需內存過大,超過了單個區塊內存大小(或其他限制)
  • 調整G1後臺線程數
    • -XX:ConcGCThreads=N:後臺線程數目
      • 默認根據ParallelGCThreads值計算得來:N = ( 2 + ParallelGCThreads ) / 4
  • 調整垃圾收集頻率
    • -XX:InitiationHeapOccupancyPercent=N:觸發併發收集週期的堆內存佔用比閾值(默認45)
  • 調整混合式垃圾收集週期
    • -XX:G1MixedGCLiveThresholdPercent=N:觸發分區回收標記的分區垃圾佔比閾值
    • -XX:G1MixedGCCountTarget=N:最大混合式GC週期數(默認8)
      • 減少此值可以幫助解決晉升失敗問題,代價是混合式GC週期停頓時間更長
    • -XX:MaxGCPauseMillis=N:設置最大停頓時間(默認200ms)
4. Survivor空間及晉升:
  • 設置Survivor空間大小
    • -XX:InitialSurvivorRatio=N:初始Survivor空間大小佔比(N爲分母)
      • survivor空間大小 = new_size / ( InitialSurvivorRatio + 2 )
    • -XX:MinSurvivorRatio=N:Survivor最大大小(注意由於N是分母,雖然參數是min,但是卻是設置的最大值)
  • 自動調節
    • -XX:TargetSurvivorRatio=N:垃圾回收後空閒空間佔比
  • 晉升閾值:對象在Survivor空間之間來回移動多少個GC週期後晉升到老年代
    • -XX:InitialTenuringThreshold=N:初始晉升閾值
    • -XX:MaxTenuringThreshold=N:最大晉升閾值
    • JVM會持續的計算,在1和最大晉升閾值中選擇合適的值
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章