Java性能優化權威指南-讀書筆記(四)-JVM性能調優-延遲


延遲指服務器處理一個請求所花費的時間,單位一般是ms、s。

本文主要講降低延遲可以做的服務器端JVM優化。

JVM延遲優化

新生代

新生代大小決定了應用平均延遲

如果平均Minor GC持續時間大於應用程序平均延遲性要求,可以適當減小新生代空間大小;

如果Minor GC頻率大於應用程序平均延遲性要求,可以適當增大新生代空間;

老年代

老年代大小決定了應用最差延遲

FullGC頻率大於應用程序最大FullGC頻率要求,可以適當增大老年代空間大小;

FullGC持續時間大於應用程序最差延遲性要求,可以使用CMS垃圾收集器;

CMS收集器調優

CMS主要特性

CMS為老年代收集器,收集線程能與應用程序線程實現最大的並行度,降低了延遲。

CMS並不進行壓縮,所以老年代使用空閑列表分配內存,在一定程度上增加了新生代晉升老年代時,耗費的時間。

但一旦老年代溢出就會觸發Stop-The-World壓縮式垃圾收集。

所以,CMS的優化大概有下面幾點:

1. 避免用盡老年代空間;

2. 解決老年代碎片化問題,解決方法包括壓縮、MinorGC回收原則;

3. 降低初始標記階段和重新標記階段占用的時間,因為這兩個階段應用程序線程會被阻塞;

Survivor空間調優

調整Survivor空間,是為了讓其有足夠空間容納存活對象足夠長的時間,直到幾個周期后對象老化,解決上面的第一、二條問題。

Survivor空間的大小可以通過下面這個參數調整:

-XX:SurvivorRatio=<ratio>

<ratio>必須大於0,-XX:SurvivorRatio=<ratio>表示單個Survivor和Eden的比率。

survivor空間大小  = –Xmn/(-XX:SurvivorRatio=<ratio> + 2)

 

監控晉升閾值

-XX:MaxTenuringThreshold=n     //設置最大晉升閾值

-XX:+PrintTenuringDistribution   //打印晉升的分布或對象年齡分布到GC日志

如下面這個晉升日志:

Desired survivor size 1114112 bytes, new threshold 1 (max 6)
- age   1:    2213864 bytes,    2213864 total

Desired survivor size 1114112 bytes是Survivor空間大小 * 目標存活率(可以設定,默認50%)

new threshold 1 JVM內部計算出的晉升閾值 (max 6)設置的晉升閾值

age   1(對象年齡代)   2213864 bytes(這個年齡對象總大小),    2213864 total(所有年齡對象總大小)

Survivor目標存活率:指Minor GC后Survivor空間占用比率,如果太大,下次Minor GC后存活的對象就有可能放不下

 

從這個日志可以看出,存活對象2213864bytes大於期望Survivor大小為1124112bytes,所以對象年齡為1時,就提升到了老年代。

解決這個問題的方法就是增大Survivor空間,存活對象大小 / 目標存活率 = Survivor空間大小,本例中大概4.5M,所以修改JVM參數為:

-Xmx512m -Xms512m -Xmn50m -XX:SurvivorRatio=5

調整后的晉升日志大概如下,這個已不是上面那個應用了,所以Survivor空間不一樣,能說明問題就行:

Desired survivor size 87359488 bytes, new threshold 15 (max 15)
- age   1:   20701528 bytes,   20701528 total
- age   2:    4924656 bytes,   25626184 total
- age   3:    3261000 bytes,   28887184 total
- age   4:    7941120 bytes,   36828304 total

調整Survivor空間的一個重要原則:

調整Survivor空間時,應保持Eden空間不變,否則會導致Minor GC頻率變小。

初始化CMS收集周期

CMS中發生的Stop-The-World壓縮式垃圾收集可以在GC日志中查找並發模式失效(concurrent mode failure)定位。

如果有這個問題,就需要調整CMS收集周期。

-XX:CMSInitiatingOccupancyFraction=<percent>    //設置CMS垃圾收集周期在老年代空間占用達到多少是啟動

-XX:+UseCMSInitiatingOccupancyOnly                  //告知JVM總是使用 CMSInitiatingOccupancyFraction比率啟動CMS,否則只是在CMS第一次啟動時

原則:CMSInitiatingOccupancyFraction設置的比率至少是老年代活躍數據的1.5倍

如果老年代空間消耗的比較慢,可以稍晚啟動CMS,即將CMSInitiatingOccupancyFraction設定的更大;

如果老年代空間消耗的很快,可以將CMSInitiatingOccupancyFraction設定的更小,但不能低於活躍數據占用的比率;

降低CMS重新標記階段占用時間

-XX:ParallelGCThreads   //控制重新標記的線程數,建議將CMS的收集線程數設置的小於默認值,否則大量GC線程會影響應用性能

-XX:+CMSScavengeBeforeRemark  //在CMS進入重新標記階段先進行一次Minor GC,可以減少引用老年代的新生代對象數量,降低重新標記階段的工作量

-XX:+ParallelRefProcEnabled    //使用多線程處理引用,不過在JDK6u25和6u26上有BUG


免責聲明!

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



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