CMS的Full GC採用壓縮式垃圾收集,在堆比較大的時候,若是full gc頻繁,會致使停頓,而且調用方阻塞、超時、甚至雪崩的狀況出現,因此下降full gc的發生頻率和須要時間,很是有必要。html
優化前java
<jvm-arg>-Xmx13312m</jvm-arg> <jvm-arg>-Xms9216m</jvm-arg> <jvm-arg>-Xmn1024m</jvm-arg> <jvm-arg>-XX:PermSize=512M</jvm-arg> <!-- 使用cms回收策略 --> <jvm-arg>-XX:+UseParNewGC</jvm-arg> <jvm-arg>-XX:+UseConcMarkSweepGC</jvm-arg> <!-- 打印gc日誌 --> <jvm-arg>-XX:+PrintGCDetails</jvm-arg> <jvm-arg>-XX:+PrintGCDateStamps</jvm-arg> <jvm-arg>-XX:+PrintHeapAtGC</jvm-arg> <jvm-arg>-Xloggc:log/gc.log</jvm-arg>
優化後:windows
<jvm-arg>-Xmx13312m</jvm-arg> <jvm-arg>-Xms13312m</jvm-arg> <jvm-arg>-Xmn5120m</jvm-arg> <jvm-arg>-XX:PermSize=512M</jvm-arg> <jvm-arg>-XX:+UseParNewGC</jvm-arg> <jvm-arg>-XX:+UseConcMarkSweepGC</jvm-arg> <!-- 每次full gc以後,進行壓縮 --> <jvm-arg>-XX:CMSFullGCsBeforeCompaction=0</jvm-arg> <!-- 老年代佔用75%進行full gc --> <jvm-arg>-XX:CMSInitiatingOccupancyFraction=75</jvm-arg> <jvm-arg>-XX:CMSMaxAbortablePrecleanTime=30000</jvm-arg> <jvm-arg>-XX:SurvivorRatio=6</jvm-arg> <jvm-arg>-XX:+PrintGCDetails</jvm-arg> <jvm-arg>-XX:+PrintGCDateStamps</jvm-arg> <jvm-arg>-XX:+PrintHeapAtGC</jvm-arg> <jvm-arg>-Xloggc:log/gc.log</jvm-arg>
將Xmx和Xms設置爲同樣大小,調大Xmnoracle
緣由jvm
調整如下參數優化
<jvm-arg>-Xmx13312m</jvm-arg> <jvm-arg>-Xms13312m</jvm-arg> <jvm-arg>-Xmn4096m</jvm-arg>
效果 ygc由每分鐘40次,下降爲10次上下 fgc時間,由以前的100ms升爲300ms日誌
時間一長,發現單次full gc時間太長,有時候長達2s,日誌中發現pre clean沒有結束,就進行了remark致使的。code
CMS: abort preclean due to time 2016-06-13T08:58:07.672+0800: 63803.570: [CMS-concurrent-abortable-preclean: 5.190/5.211 secs] [Times: user=12.15 sys=1.38, real=5.21 secs] 2016-06-13T08:58:07.677+0800: 63803.575: [GC[YG occupancy: 2652667 K (3774912 K)]63803.576: [Rescan (parallel) , 1.9969650 secs]63805.573: [weak refs processing, 0.0280880 secs] [1 CMS-remark: 7082120K(9437184K)] 9734787K(13212096K), 2. 0288350 secs] [Times: user=25.39 sys=0.11, real=2.03 secs]
pre clean用於保證remark的順利進行,若是pre clean階段沒有結束,就remark,會致使remark階段延長,pre clean默認是5s,延長至30s。 調整如下參數:htm
-XX:CMSMaxAbortablePrecleanTime=30000
效果 優化後,日發gc日誌中沒有abort preclean的現象發生了。對象
前兩次優化已經見到效果了,可是full gc仍是比較多,且持續時間比較長,增長配置,打印對象年齡:
-XX:+PrintTenuringDistribution
由於經過ygc的對象進入老年代,是按照年齡計算的,這個年齡默認是15,可是是動態調整的,因此加這個參數,再觀察一下。 查看日誌能夠看出,對象動態調全年齡是4,過低了,對象才4歲,就進入老年代了。
2016-06-14T19:51:31.639+0800: 770.958: [GC 770.959: [ParNew Desired survivor size 214728704 bytes, new threshold 4 (max 4) - age 1: 27368432 bytes, 27368432 total - age 2: 12108344 bytes, 39476776 total - age 3: 11933416 bytes, 51410192 total - age 4: 5568312 bytes, 56978504 total
默認配置的15,怎麼才4就進入老年代了,原來jvm是動態對象年齡斷定的。
爲了能更好地適應不一樣程序的內存情況,虛擬機並不老是要求對象的年齡必須達到Max Tenuring Threshold才能晉升老年代 若是在Survivor空間中相同年齡全部對象大小的總和大於Survivor空間的一半,年齡大於或等於該年齡的對象就能夠直接進入老年代,無須等到Max Tenuring Threshold中要求的年齡。
既然取決於survivor的大小,調大survivor
修改配置:
-Xmn5120m -XX:SurvivorRatio=6
調整後,age已經到15了。
2016-06-15T10:11:28.921+0800: 631.926: [GC 631.927: [ParNew Desired survivor size 335544320 bytes, new threshold 15 (max 15) - age 1: 44556600 bytes, 44556600 total - age 2: 41122176 bytes, 85678776 total - age 3: 14339240 bytes, 100018016 total - age 4: 19359008 bytes, 119377024 total - age 5: 13662592 bytes, 133039616 total - age 6: 21144880 bytes, 154184496 total - age 7: 17551328 bytes, 171735824 total - age 8: 5390312 bytes, 177126136 total - age 9: 8580176 bytes, 185706312 total - age 10: 7921328 bytes, 193627640 total - age 11: 17954784 bytes, 211582424 total - age 12: 6197064 bytes, 217779488 total - age 13: 7211632 bytes, 224991120 total - age 14: 10837872 bytes, 235828992 total - age 15: 10255800 bytes, 246084792 total : 4236533K->288272K(4587520K), 0.0551150 secs] 4916941K->973217K(12976128K), 0.0557070 secs] [Times: user=0.80 sys=0.01, real=0.06 secs] Heap after GC invocations=68 (full 1):