JVM优化过程全记录
今天看JVM群里有人發了一個GC情況,讓人幫忙看優化的,于是我也湊熱鬧發了出來想讓群里的大神們指導優化一下,以下是優化過程記錄.
一開始我貼了下面的兩張圖
jstat看GC記錄
jstat -gcutil pid 1000 20
jcmd看VM參數(第一次使用這個命令)
jcmd pid VM.flags
可以看到YGC了8W多次,FGC有1100+,相比較另一個發出來求教的,我這個更糟糕,他的是運行了3天左右 FGC370次
然后飛神讓我看下運行時間
ps -p pid -o etime
我的也是跑了3天左右,感覺優化空間非常的大
又讓我拉了JVM配置
jinfo -flags pid(沒權限,沒執行成功)
ps aux | grep pid
發現我的JVM完全沒做過優化,據我自己的印象,就改過PermSize,因為這個OOM過,所以調大了一點。
然后飛神給了我一份他之前用過的配置
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時間和次數已經降了很多了,但是還是沒達到期望的結果,考慮到這個程序短時間的活對象是比較多的,可以通過調整年輕代和老年代的內存占比來減少因為年輕代內存不足導致晉升到老年代的對象。
現在已經離開這個項目了,所以后面就沒有再繼續優化了,以后再有這方面的實踐重新寫文章記錄。
總結
以上是生活随笔為你收集整理的JVM优化过程全记录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: intellij idea run co
- 下一篇: asp.net signalR 专题——