今天看JVM羣裏有人發了一個GC狀況,讓人幫忙看優化的,因而我也湊熱鬧發了出來想讓羣裏的大神們指導優化一下,如下是優化過程記錄.java
一開始我貼了下面的兩張圖tomcat
jstat看GC記錄jstat -gcutil pid 1000 20
jvm
jcmd看VM參數(第一次使用這個命令)jcmd pid VM.flags
優化
能夠看到YGC了8W屢次,FGC有1100+,相比較另外一個發出來求教的,我這個更糟糕,他的是運行了3天左右 FGC370次spa
而後飛神讓我看下運行時間ps -p pid -o etime
日誌
個人也是跑了3天左右,感受優化空間很是的大code
又讓我拉了JVM配置jinfo -flags pid
(沒權限,沒執行成功)ps aux | grep pid
orm
發現個人JVM徹底沒作過優化,據我本身的印象,就改過PermSize,由於這個OOM過,因此調大了一點。server
而後飛神給了我一份他以前用過的配置JAVA_OPTS="-Xms2g -Xmx2g -Xmn512m -XX:MaxPermSize=256m -server -Xss256k -XX:PermSize=128M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/data/log/gclog/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/log/jvmdump/jvm.bin -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:+TieredCompilation -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime -XX:+PrintHeapAtGC
對象
並囑咐了一句loggc和dumpPath提早mkdir
由於已是週五晚上了,我沒有權限直接修改這個配置,因此準備下週一再配上去看效果。
萬萬沒想到,回家路上,笨神出來講話了,要我看下存活實例
jmap -histo:live pid
因爲沒有開啓GC日誌,因而笨神讓我開着jstat(飛神提到jstat -gccause pid
能夠跟蹤gc狀況),而後在另外一個窗口執行jmap -histo:live
剛開始沒明白,後來才知道原來這個命令能夠觸發Full GC
能夠看到執行了Full GC之後Old區從90%降到了79%,FGC效果不好,說明活對象太多了。
回過頭去看jmap實例,發現AtomicInteger
這個類對象特別的多,居然有300多萬個實例,已是top2了。
翻看代碼沒有發現有使用這個類的地方,初步懷疑是依賴的jar包使用的,笨神建議dump用MAT分析一下。
dump命令導出文件jmap -dump:format=b,file=pid.dump pid
檢查了一下項目代碼後,發現了問題,項目代碼就不貼了
項目中有一個統計API調用次數的類使用了AtomicInteger
,在這個類裏針對每一個用戶都會生成大概六七十個AtomicInteger
實例,每次上報過數據以後只是簡單的把值設置爲0,致使負責統計的實例一直持有這些AtomicInteger
,並且隨着新用戶的不斷增長,這些實例數量還會持續增加,最終會致使內存溢出。
修改完這個BUG,從新上線後,跑了一段時間查看gc狀況
能夠看到比以前好一些了 可是FGC的次數仍是比較多,照這狀況下去一天的FGC估計會有200+,這固然是不可接受的(前面說的另外一我的370次FGC,飛神說若是是跑了半年的話還能夠接受)。
看了飛神推薦的阿里畢玄大師的文章爲何不建議
因而準備先不上CMS GC,就簡單的把Xms,Xmn和GC日誌配置了一下
-Xms2048m -Xmx2048m -XX:PermSize=128m -XX:MaxPermSize=128m -Xss256k -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/data/project/delivery_v9/code/logs/gc.log -XX:GCLogFileSize=50m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/project/delivery_v9/tomcat/jvmdump/jvm.dump
運行了一天左右看下對比結果
未配置
已配置
能夠看到配置完之後對GC影響仍是挺大的(不論是YGC仍是FGC),固然這也是必然的,畢竟沒有配置的機器初始內存比較小,在不斷擴容的過程當中會頻繁的GC,並且這個時候其實沒配置的那臺機器內存尚未擴充到上限,在資源充足的狀況下,這種動態擴容顯然是徹底沒有必要的。
配置完的機器雖然GC時間和次數已經降了不少了,可是仍是沒達到指望的結果,考慮到這個程序短期的活對象是比較多的,能夠經過調全年輕代和老年代的內存佔比來減小由於年輕代內存不足致使晉升到老年代的對象。
如今已經離開這個項目了,因此後面就沒有再繼續優化了,之後再有這方面的實踐從新寫文章記錄。