延遲指服務器處理一個請求所花費的時間,單位通常是ms、s。html
本文主要講下降延遲能夠作的服務器端JVM優化。java
新生代大小決定了應用平均延遲服務器
若是平均Minor GC持續時間大於應用程序平均延遲性要求,能夠適當減少新生代空間大小;多線程
若是Minor GC頻率大於應用程序平均延遲性要求,能夠適當增大新生代空間;併發
老年代大小決定了應用最差延遲性能
FullGC頻率大於應用程序最大FullGC頻率要求,能夠適當增大老年代空間大小;優化
FullGC持續時間大於應用程序最差延遲性要求,可使用CMS垃圾收集器;ui
CMS爲老年代收集器,收集線程能與應用程序線程實現最大的並行度,下降了延遲。spa
CMS並不進行壓縮,因此老年代使用空閒列表分配內存,在必定程度上增長了新生代晉升老年代時,耗費的時間。線程
但一旦老年代溢出就會觸發Stop-The-World壓縮式垃圾收集。
因此,CMS的優化大概有下面幾點:
1. 避免用盡老年代空間;
2. 解決老年代碎片化問題,解決方法包括壓縮、MinorGC回收原則;
3. 下降初始標記階段和從新標記階段佔用的時間,由於這兩個階段應用程序線程會被阻塞;
調整Survivor空間,是爲了讓其有足夠空間容納存活對象足夠長的時間,直到幾個週期後對象老化,解決上面的第1、二條問題。
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中發生的Stop-The-World壓縮式垃圾收集能夠在GC日誌中查找併發模式失效(concurrent mode failure)定位。
若是有這個問題,就須要調整CMS收集週期。
-XX:CMSInitiatingOccupancyFraction=<percent> //設置CMS垃圾收集週期在老年代空間佔用達到多少是啓動
-XX:+UseCMSInitiatingOccupancyOnly //告知JVM老是使用 CMSInitiatingOccupancyFraction比率啓動CMS,不然只是在CMS第一次啓動時
原則:CMSInitiatingOccupancyFraction設置的比率至少是老年代活躍數據的1.5倍
若是老年代空間消耗的比較慢,能夠稍晚啓動CMS,即將CMSInitiatingOccupancyFraction設定的更大;
若是老年代空間消耗的很快,能夠將CMSInitiatingOccupancyFraction設定的更小,但不能低於活躍數據佔用的比率;
-XX:ParallelGCThreads //控制從新標記的線程數,建議將CMS的收集線程數設置的小於默認值,不然大量GC線程會影響應用性能
-XX:+CMSScavengeBeforeRemark //在CMS進入從新標記階段先進行一次Minor GC,能夠減小引用老年代的新生代對象數量,下降從新標記階段的工做量
-XX:+ParallelRefProcEnabled //使用多線程處理引用,不過在JDK6u25和6u26上有BUG