本文詳細說明了Java應用運行過程中幾種常見的JVM相關問題,并給出了問題排查步驟。
一、堆中OOM
現象:Java線程負載過高,JVM內存幾乎占滿,甚至拋出java.lang.OutOfMemoryError錯誤。
思路:通過jmap能查看到對內存中實例,可以查看到哪些類的實例比較多,排查出OOM原因。
工具:jmap
步驟:
1.查看實例信息:
jmap -histo 14660 #查看歷史生成的實例
jmap -histo:live 14660 #查看當前存活的實例,執(zhí)行過程中可能會觸發(fā)一次full gc
2.查看堆信息:jmap -heap
3.堆內存dump下來:
(1)jmap -dump:format=b,file=eureka.hprof 14660
(2)使用jvisualvm命令工具導入該dump文件分析
二、死鎖排查
現象:多個線程處于死鎖狀態(tài),無法再正常執(zhí)行。
背景:當兩個線程互相加了對方所依賴的鎖時就會進入死鎖狀態(tài),例如執(zhí)行以下代碼會進入死鎖狀態(tài):
public class Test1 {
public static void main(String[] args) {
Object lock = new Object();
Object lock1 = new Object();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock1) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock) {
}
}
}
}).start();
}
}
思路:通過jmap能看到所有線程的狀態(tài),但線程狀態(tài)處于blocked時候就是被加鎖的狀態(tài)中。
工具:jmap
步驟:
-
jps 查看進程號
-
用jstack 查找死鎖狀態(tài)中線程。
"Thread-1" 線程名
tid=0x000000079582bc98 線程id
nid=0x3e03 線程對應的本地線程標識nid
java.lang.Thread.State: BLOCKED 線程狀態(tài)
三、CPU飆升
現象:JVM的CPU飆升
思路:通過top查看出占用最大的java線程id,再通過命令top -Hp找到該線程下關聯(lián)的進程id,找到占用cpu最高的線程id,將其轉換為十六進制,在通過jstack來查看進程狀態(tài)
工具:top+jstack
步驟:
- 用top命令查找出CPU占用最大的java進程和下面的線程;
查找CPU占用最高的進程:top 查找該進程下面的線程:top -Hp <java_pid>
,可以看到該進程下所有子線程,可以找到占用CPU最高的線程Id,可以用命令:printf "%x\n" <線程id>
將十進制線程id轉為十六進制,便于后面jstack命令使用打印GC日志:jstat -gc <java_pid> 5000
- 用jstack查找出對應線程的日志信息;
通過進程id查看棧內信息:jstack <java_pid> | grep <線程id十六進制值> -A 30
(-A 30表示向下打印30行)
總結:cpu飆升可能的原因大概為:
-
代碼存在死循環(huán),導致消耗cpu;
-
代碼一直在創(chuàng)建大對象,導致頻繁GC,這個時候內存占用率也會很高;
四、頻繁Full GC
問題說明:系統(tǒng)中某服務為圖方便緩存使用一個hashmap,運行過程中會不斷往里面放緩存數據,但是沒有考慮這個map的容量問題,結果這個緩存map越來越大,一直占用著老年代的很多空間,時間長了就會導致full gc非常頻繁,這就是一種內存泄漏,對于一些老舊數據沒有及時清理導致一直占用著寶貴的內存資源,時間長了除了導致full gc,還有可能導致OOM。
這種情況完全可以考慮采用一些成熟的JVM級緩存框架來解決,比如guava、ehcache等自帶一些LRU數據淘汰算法的框架來作為JVM級的緩存。
工具:jstat
步驟:
- jstat -gc 可以評估程序內存使用及GC壓力整體情況
- S0C:第一個幸存區(qū)的大小,單位KB
- S1C:第二個幸存區(qū)的大小
- S0U:第一個幸存區(qū)的使用大小
- S1U:第二個幸存區(qū)的使用大小
- EC:伊甸園區(qū)的大小
- EU:伊甸園區(qū)的使用大小
- OC:老年代大小
- OU:老年代使用大小
- MC:方法區(qū)大小(元空間)
- MU:方法區(qū)使用大小
- CCSC:壓縮類空間大小
- CCSU:壓縮類空間使用大小
- YGC:年輕代垃圾回收次數
- YGCT:年輕代垃圾回收消耗時間,單位s
- FGC:老年代垃圾回收次數
- FGCT:老年代垃圾回收消耗時間,單位s
- GCT:垃圾回收消耗總時間,單位s
優(yōu)化思路:簡單來說就是盡量讓每次Young GC后的存活對象都留存在年輕代里,盡量別讓對象進入老年代,盡量減少Full GC的頻率,避免頻繁Full GC對JVM性能的影響。
JVM參數說明:
-Xms1536M -Xmx1536M -Xmn512M -Xss256K -XX:SurvivorRatio=6 -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly
文章來源:http://www.zghlxwxcb.cn/news/detail-699807.html
本文由博客一文多發(fā)平臺 OpenWrite 發(fā)布!文章來源地址http://www.zghlxwxcb.cn/news/detail-699807.html
到了這里,關于JVM問題排查的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!