JVM參數調優總結


一、前言

  要想成為一名高級Java開發具備JVM調優的能力必不可少,能夠根據項目實際情況進行JVM調優的前提是理解JVM原理和常用JVM參數的含義及作用,雖然《深入理解Java虛擬機》這本書已經寫了很多,但是里面的提到的參數比較散亂,故寫此文總結。

二、JVM參數

JVM相關參數

名稱 作用 默認值 備注
-Xms 初始堆大小 物理內存的1/64(<1GB) 默認(MinHeapFreeRatio參數可以調整)空余堆內存小於40%時,
JVM就會增大堆直到-Xmx的最大限制.
-Xmx 最大堆大小 物理內存的1/4(<1GB) 默認(MaxHeapFreeRatio參數可以調整)空余堆內存大於70%時,
JVM會減少堆直到 -Xms的最小限制
-Xmn 年輕代大小(1.4or lator) 注意:此處的大小是(eden+ 2 survivor space).與jmap-heap中顯示的
New gen是不同的。
整個堆大小=年輕代大小 + 年老代大小 + 持久代大小.
增大年輕代后,將會減小年老代大小.此值對系統性能影響較大,
Sun官方推薦配置為整個堆的3/8
-XX:NewSize 設置年輕代大小(for 1.3/1.4)
-XX:MaxNewSize 年輕代最大值(for 1.3/1.4)
-XX:PermSize 設置持久代(perm gen)初始值 物理內存的1/64
-XX:MaxPermSize 設置持久代最大值 物理內存的1/4
-Xss 每個線程的堆棧大小 JDK5.0以后每個線程堆棧大小為1M,以前每個線程堆棧大小為256K.
更具應用的線程所需內存大小進行 調整.在相同物理內存下,
減小這個值能生成更多的線程.但是操作系統對一個進程內的線程數還是有限制的,
不能無限生成,經驗值在3000~5000左右一般小的應用, 如果棧不是很深,
應該是128k夠用的 大的應用建議使用256k。這個選項對性能影響比較大,需要嚴格的測試。
-XX:ThreadStackSize Thread Stack Size (0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.]
-XX:NewRatio 年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代) 默認2 -XX:NewRatio=4表示年輕代與年老代所占比值為1:4,年輕代占整個堆棧的1/5。Xms=Xmx並且設置了Xmn的情況下,該參數不需要進行設置。
-XX:SurvivorRatio Eden區與Survivor區的大小比值 8 設置為8,則兩個Survivor區與一個Eden區的比值為2:8,一個Survivor區占整個年輕代的1/10
-XX:LargePageSizeInBytes 內存頁的大小不可設置過大, 會影響Perm的大小 =128m
-XX:+UseFastAccessorMethods 原始類型的快速優化
-XX:+DisableExplicitGC 關閉System.gc() 這個參數需要嚴格的測試
-XX:MaxTenuringThreshold 垃圾最大年齡 默認15 如果設置為0的話,則年輕代對象不經過Survivor區,直接進入年老代. 對於年老代比較多的應用,可以提高效率.
如果將此值設置為一個較大值,則年輕代對象會在Survivor區進行多次復制,這樣可以增加對象再年輕代的存活 時間,增加在年輕代即被回收的概率該參數只有在串行GC時才有效(待考證)。
如果在Survivor空間中相同年齡所有對象大小的總和大於Survivor空間的一半,年齡大於或等於該年齡的對象就可以直接進入老年代,無需等到-XX:MaxTenuringThreshold要求的年齡。
-XX:+AggressiveOpts 加快編譯
-XX:+UseBiasedLocking 是否啟用偏向鎖(since1.6) 默認開啟 如果程序中大多數鎖都總是被不同的線程訪問,關閉偏向鎖可能性能更好。
-Xnoclassgc 是否要對類型回收
-XX:SoftRefLRUPolicyMSPerMB 每兆堆空閑空間中SoftReference的存活時間 1s softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap
-XX:PretenureSizeThreshold 對象超過多大是直接在老年代分配 單位字節,該參數只對新生代收集器Serial和ParNew有效
另一種直接在舊生代分配的情況是大的數組對象,且數組中無外部引用對象.
-XX:TLABWasteTargetPercent TLAB占eden區的百分比 1%
-XX:+CollectGen0First FullGC時是否先YGC false

並行器相關參數

名稱 含義 默認值 作用
-XX:+UseParallelGC Full GC采用parallel MSC(此項待驗證) 選擇垃圾收集器為並行收集器.此配置僅對年輕代有效.即上述配置下,年輕代使用並發收集,而年老代仍舊使用串行收集.(此項待驗證)
-XX:+UseParNewGC 設置年輕代為並行收集 可與CMS收集同時使用,JDK5.0以上,JVM會根據系統配置自行設置,所以無需再設置此值
-XX:ParallelGCThreads 並行收集器的線程數 此值最好配置與處理器數目相等 同樣適用於CMS
-XX:+UseParallelOldGC 老年代垃圾收集方式為並行收集(Parallel Compacting) since 1.6
XX:MaxGCPauseMillis 每次年輕代垃圾回收的最長時間(最大暫停時間) 如果無法滿足此時間,JVM會自動調整年輕代大小,以滿足此值.
-XX:+UseAdaptiveSizePolicy 自動選擇年輕代區大小和相應的Survivor區比例 設置此選項后,並行收集器會自動選擇年輕代區大小和相應的Survivor區比例,
以達到目標系統規定的最低響應時間或者收集頻率等,此值建議使用並行收集器時,一直打開.
-XX:GCTimeRatio 設置垃圾回收時間占程序運行時間的百分比 公式為1/(1+n)
-XX:+ScavengeBeforeFullGC Full GC前調用YGC true Do young generation GC prior to a full GC. (Introduced in 1.4.1.)

CMS相關參數

名稱 含義 默認值 作用
-XX:+UseConcMarkSweepGC 使用CMS收集器 開啟后默認新生代使用ParNew收集器
-XX:+AggressiveHeap 試圖是使用大量的物理內存長時間大內存使用的優化,能檢查計算資源(內存, 處理器數量)
至少需要256MB內存
大量的CPU/內存,(在1.4.1在4CPU的機器上已經顯示有提升)
-XX:CMSFullGCsBeforeCompaction 執行多少次不整理空間的Full GC之后,
下一次進入進入Full GC前進行整理
默認0(每次Full GC后都整理) jdk9后廢棄
-XX:+CMSParallelRemarkEnabled 降低標記停頓
-XX+UseCMSCompactAtFullCollection 在FULL GC的時候,對年老代的壓縮 默認開啟 CMS是不會移動內存的,因此,這個非常容易產生碎片,導致內存不夠用,
因此, 內存的壓縮這個時候就會被啟用。增加這個參數是個好習慣。
可能會影響性能,但是可以消除碎片
-XX:+UseCMSInitiatingOccupancyOnly 使用手動定義初始化定義開始CMS收集 禁止hostspot自行觸發CMS GC
-XX:CMSInitiatingOccupancyFraction=70 使用cms作為垃圾回收使用70%后開始CMS收集 92(since 1.6) 為了保證不出現promotion failed(見下面介紹)錯誤,
該值的設置需要滿足以下公式CMSInitiatingOccupancyFraction計算公式
-XX:CMSInitiatingPermOccupancyFraction 設置Perm Gen使用到達多少比率時觸發 92
-XX:+CMSIncrementalMode 設置為增量模式 不再提倡使用
-XX:+CMSClassUnloadingEnabled 相對於並行收集器,CMS收集器默認不會對永久代進行垃圾回收。如果希望對永久代進行垃圾回收,可用設置標志-XX:+CMSClassUnloadingEnabled。
-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses 保證當有系統GC調用時,永久代也被包括進CMS垃圾回收的范圍內
-XX:+ExplicitGCInvokesConcurrent 命令JVM無論什么時候調用系統GC,都執行CMS GC,而不是Full GC。(默認調用系統GC時CMS收集器會觸發一次Full GC)

G1相關參數

名稱 含義 默認值 作用
-XX:+UseG1GC 使用G1收集器 主流且想更精確的把控停頓延遲(通常堆內存大於8g時使用G1才會效果更好,小堆情況CMS更佳)
-XX:G1HeapRegionSize G1的每個Region占比大小,值是 2 的冪,范圍是 1 MB 到 32 MB 之間。目標是根據最小的 Java 堆大小划分出約 2048 個區域。一般不改 默認 所以g1最多支持64G的堆
-XX:G1NewSizePercent G1初始化的時候新生代占比大小 默認是5%
-XX:G1MaxNewSizePercent 默認60 新生代最大值默認 60% 建議不要調大 采取默認
-XX:InitiatingHeapOccupancyPerecnt 45% G1老年代占比達到多少的適合開始Mixed gc
-XX:G1MixedGCLiveThresholdPercent 85% 每個Region對象中存活數目的占比達到多少就不會回收
-XX:GCMixedGCCountTarget 默認8次 G1混合gc的回收階段 做幾次重復回收動作

輔助參數

名稱 含義 默認值 作用
-XX:+PrintGC 輸出形式:
[GC 118250K->113543K(130112K), 0.0094143 secs]
[Full GC 121376K->10414K(130112K), 0.0650971 secs]
-XX:+PrintGCDetails 輸出形式:
[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs]
[GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]
-XX:+PrintGCTimeStamps
-XX:+PrintGC:PrintGCTimeStamps 可與-XX:+PrintGC -XX:+PrintGCDetails混合使用,
輸出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]
-XX:+PrintGCApplicationStoppedTime 打印垃圾回收期間程序暫停的時間.可與上面混合使用 輸出形式:Total time for which application threads were stopped: 0.0468229 seconds
-XX:+PrintGCApplicationConcurrentTime 打印每次垃圾回收前,程序未中斷的執行時間.可與上面混合使用 輸出形式:Application time: 0.5291524 seconds
-XX:+PrintHeapAtGC 打印GC前后的詳細堆棧信息
-Xloggc:filename 把相關日志信息記錄到文件以便分析.與上面幾個配合使用
-XX:+PrintClassHistogram garbage collects before printing the histogram.
-XX:+PrintTLAB 查看TLAB空間的使用情況
-XX:+PrintTenuringDistribution 查看每次minor GC后新的存活周期的閾值 Desired survivor size 1048576 bytes, new threshold 7 (max 15)
new threshold 7即標識新的存活周期的閾值為7。

三、調優策略

JVM調優一般來說要根據實際情況,不斷調整參數來找到最佳的參數設置,但是有些經驗是通用的。
經驗:

  1. XMX和XMS設置一樣大,MaxPermSize和MinPermSize設置一樣大,這樣可以減輕伸縮堆大小帶來的壓力。
  2. 用64位操作系統,Linux下64位的jdk比32位jdk要慢一些,但是吃得內存更多,吞吐量更大
  3. 使用CMS的好處是用盡量少的新生代,經驗值是128M-256M, 然后老生代利用CMS並行收集, 這樣能保證系統低延遲的吞吐效率。 實際上cms的收集停頓時間非常的短,2G的內存, 大約20-80ms的應用程序停頓時間
  4. 系統停頓的時候可能是GC的問題也可能是程序的問題,多用jmap和jstack查看,或者killall -3 java,然后查看java控制台日志,能看出很多問題。
  5. 仔細了解自己的應用,如果用了緩存,那么年老代應該大一些,緩存的HashMap不應該無限制長,建議采用LRU算法的Map做緩存,LRUMap的最大長度也要根據實際情況設定。
  6. 采用並發回收時,年輕代小一點,年老代要大,因為年老大用的是並發回收,即使時間長點也不會影響其他程序繼續運行,網站不會停頓。
  7. 一般避免年輕代設置過小,過小會導致:1.YGC次數更加頻繁 2.可能導致YGC對象直接進入老年代,如果此時老年代滿了,會觸發FGC.

使用CMS有幾個問題需要注意:

promotion failed

  • 問題原因:

該問題是在進行Minor GC時,Survivor Space放不下,對象只能放入老年代,而此時老年代也放不下造成的。(promotion failed時老年代CMS還沒有機會進行回收,又放不下轉移到老年代的對象,因此會出現下一個問題concurrent mode failure,需要stop-the-wold 降級為GC-Serail Old)。

  • 解決方案:

去掉Survivor空間,設置-XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0即可,存活的對象直接進去老年代。

concurrent mode failure

  • 解決方案:

    通過參數-XX:CMSInitiatingOccupancyFraction設置合理的CMS的觸發百分比,保證提前觸發Full GC避免老年代空間不夠的問題。

CMSInitiatingOccupancyFraction的計算公式:

上面介紹了promontion faild產生的原因是EDEN空間不足的情況下將EDEN與From survivor中的存活對象存入To survivor區時,To survivor區的空間不足,再次晉升到old gen區,而old gen區內存也不夠的情況下產生了promontion faild從而導致full gc.那可以推斷出:eden+from survivor < old gen區剩余內存時,不會出現promontion faild的情況,即:
(Xmx-Xmn)*(1-CMSInitiatingOccupancyFraction/100)>=(Xmn-Xmn/(SurvivorRatior+2)) 進而推斷出:

CMSInitiatingOccupancyFraction <=((Xmx-Xmn)-(Xmn-Xmn/(SurvivorRatior+2)))/(Xmx-Xmn)*100

例如:

當xmx=128 xmn=36 SurvivorRatior=1時 CMSInitiatingOccupancyFraction<=((128.0-36)-(36-36/(1+2)))/(128-36)*100 =73.913

當xmx=128 xmn=24 SurvivorRatior=1時 CMSInitiatingOccupancyFraction<=((128.0-24)-(24-24/(1+2)))/(128-24)*100=84.615…

當xmx=3000 xmn=600 SurvivorRatior=1時 CMSInitiatingOccupancyFraction<=((3000.0-600)-(600-600/(1+2)))/(3000-600)*100=83.33

空間碎片問題

  • 問題原因:

CMS是基於“標記-清除”算法的收集器,如果GC后有大量的空間碎片產生,空間碎片很多后分配大對象就會出現老年代還有很多空間但是無法找到連續的空間來分配,從而不得不觸發Full GC。

  • 解決方案:

-XX:UseCMSCompactAtFullCollection -XX:CMSFullGCBeforeCompaction=0,設置每次Full GC之后都進行碎片整理。

網上某牛人的配置:

$JAVA_ARGS
.=
"
-Dresin.home=$SERVER_ROOT
-server
-Xms6000M
-Xmx6000M
-Xmn500M
-XX:PermSize=500M
-XX:MaxPermSize=500M
-XX:SurvivorRatio=65536
-XX:MaxTenuringThreshold=0
-Xnoclassgc
-XX:+DisableExplicitGC
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=0
-XX:+CMSClassUnloadingEnabled
-XX:-CMSParallelRemarkEnabled
-XX:CMSInitiatingOccupancyFraction=90
-XX:SoftRefLRUPolicyMSPerMB=0
-XX:+PrintClassHistogram
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-Xloggc:log/gc.log
";

補上一個JVM參數檢查優化的網站:https://console.perfma.com/

示例
示例

參考:
《JVM參數設置、分析》
《關於Jvm知識看這一篇就夠了》
《深入理解Java虛擬機》第三版


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM