Jvm故障問題排查以及Jvm調優總結
為了學習jvm故障問題的排查,寫了一個例子來驗證,在我之前服務器上部署的一個音樂網站的項目里加了一段代碼。
輕語音樂網站項目地址:https://github.com/Linliquan/springboot-music
如下:
在一個音樂搜索方法getSongRearch中加了一個for循環,循環一億次創建HashMap對象。
項目啟動部署后,在頁面上模糊搜索歌曲“你”,發現搜索緩慢。
大約十幾秒后才搜索出來
打印的日志:
排查過程:
1. 使用 ps -ef | grep java 命令找到相應的進程pid,pid = 24314
2. 使用 top 命令,查看cup占用情況。如圖,id為24314的進程,cpu占用率為99%
3. 使用 top -Hp pid 命令,查看 pid=24314 進程下的各個線程cpu占用情況。
4. 使用 printf "%x" tid 命令,將占用cpu比較高的線程的 tid = 24335 轉化為十六進制,34335的十六進制為 5f0f
5. 使用 jstack pid| grep 十六進制 -A20 命令,如 jstack 24314 | grep 5f0f -A20 打印20行線程的堆棧信息。
grep -A是顯示匹配后和它后面的n行,-B是顯示匹配行和它前面的n行,-C是匹配行和它前后各n行。
如圖可以看到,MusicLinkController 的 getSongRearch 方法的第180行代碼有問題,並且線程的狀態為RUNNABLE。
這樣就可以找出相應有問題的代碼
進一步排查:
1.使用 jmap -histo pid | head 命令,查看堆內存情況
2.使用 jmap -heap pid,查看堆內存情況
3.使用 jstat -gc pid 命令,查看各個區內存使用情況
4.使用 jstat -gcutil 24314命令,查看各區容量使用率,如圖老年代使用率為96.6%。
5.使用jstat -gc 24314 100 10,每隔100ms打印一次,打印5次
S0C:第一個幸存區的大小 S1C:第二個幸存區的大小 S0U:第一個幸存區的使用大小 S1U:第二個幸存區的使用大小 EC:伊甸園區的大小 EU:伊甸園區的使用大小 OC:老年代大小 OU:老年代使用大小 MC:方法區大小 MU:方法區使用大小 CCSC:壓縮類空間大小 CCSU:壓縮類空間使用大小 YGC:年輕代垃圾回收次數 YGCT:年輕代垃圾回收消耗時間 FGC:老年代垃圾回收次數 FGCT:老年代垃圾回收消耗時間 GCT:垃圾回收消耗總時間
年輕帶分三個區:1個E,2個S區。
1.所有對象在E區分配內存,E區和2個S區初始化為空
2.E區滿后,對象無法分配內存,觸發GC
3.第一次GC,就是把E區活對象移到S0區
4.第二次GC,E區和S0區的活對象合並,往S1區轉移
5.第三次GC,E區和S1區的活對象合並,往S0區轉移,此后重復步驟:4,5
6.如果活對象存活時間達到一定長度或者根據動態年齡判定法,則轉移到年老代。
由下圖中也可以看得出來
6.設置jvm參數
-Xms :初始堆大小,-Xmn:最大堆大小
7. 使用jmap -heap pid命令,可見新生代為200M,老年代為400M,且為1:2。
jvm參數