1. 程式人生 > 其它 >JVM問題排查手冊

JVM問題排查手冊

技術標籤:JVM

jstack

當前jvm 1 執行緒數統計:
jstack 1 |grep ‘tid’| wc -l (linux 64位系統中jvm執行緒預設棧大小為1MB)

檢視程序 1 中執行緒狀態統計
jstack 1 | grep java.lang.Thread.State | awk ‘{print $2}’ | sort | uniq -c

或者
jstack 1 > stack.txt (方便分析)
cat stack.txt | grep ‘tid’| wc -l
cat stack.txt | grep java.lang.Thread.State | awk ‘{print $2}’ | sort | uniq -c

檢視堆記憶體使用情況:

JDK9之前:
jmap -heap 1

若報錯:
解決:https://blog.csdn.net/whq12789/article/details/98941294
http://debuginfo.centos.org/7/x86_64/java-1.8.0-openjdk-debuginfo-1.8.0.212.b04-0.el7_6.x86_64.rpm

JDK9及之後:
jhsdb jmap --heap --pid 1

jmap -histo:live 1| head -n 30

jmap -dump:live,format=b,file=heap.hprof 1

jmap -dump:format=b,file=heap001.hprof 1

gc日誌輸出到檔案
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:gc.log

記憶體溢位時,堆疊資訊輸出到檔案
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/heap.hprof

垃圾收集統計摘要:

jstat -gcutil pid interval times

jstat -gcutil 1 1000 20

檢視gc發生的詳細原因:
jstat -gccause pid interval times

類載入資訊相關

jstat -class 1

至於JVM預設啟動引數,可以通過命令
java -XX:+PrintCommandLineFlags -version


檢視執行時所有引數:
java -XX:+PrintFlagsFinal -version

檢視執行中java設定的所有修改的引數:
jinfo -flags 1

檢視執行中的java例項某個引數:
jinfo -flag InitialHeapSize 1
jinfo -flag MaxHeapSize 1
jinfo -flag UseCompressedOops 1
jinfo -flag NativeMemoryTracking 1
jinfo -flag UseG1GC 1

檢視Eden 和 兩個 Survivor 區域比例:
jinfo -flag SurvivorRatio 1

檢視新生代 ( Young ) 與老年代 ( Old ) 的比例:
jinfo -flag NewRatio 1

系統層面記憶體分析策略:

https://copyfuture.com/blogs-details/20190811152052100jam7iw5128mxs5h

堆外記憶體 jcmd

因為通常的垃圾收集日誌等記錄,並不包含 Direct Buffer 等資訊,所以 Direct Buffer 記憶體診斷也是個比較頭疼的事情。
在 JDK 8 之後的版本,使用 Native Memory Tracking ( NMT )特性來進行診斷,你可以在程式啟動時加上下面引數:
-XX:NativeMemoryTracking={off|summary|detail}
off: 預設關閉
summary: 只統計各個分類的記憶體使用情況.
detail: Collect memory usage by individual call sites.

// 列印 NMT 資訊
jcmd VM.native_memory detail

// 進行 baseline,以對比分配記憶體變化
jcmd VM.native_memory baseline

// 進行 diff,對比分配記憶體變化
jcmd VM.native_memory detail.diff

jcmd 6 VM.native_memory summary

檢視系統記憶體概況 top/free

檢視程序的記憶體概況 pmap

  1. pmap -x 1

  2. 每隔兩秒鐘列印總的記憶體佔用量:
    while true; do pmap -x 28056 | tail -1; sleep 2; done

列舉出正在使用的檔案 lsof

https://blog.csdn.net/iteye_8381/article/details/82485392

  1. 列出所有tcp 網路連線資訊: lsof -i tcp | wc -l (數量)
  2. 顯示某個程序號下開啟的檔案量: lsof -p processId. 例如: lsof -p 1
  3. /proc/sys/fs/file-nr,可以看到整個系統目前使用的檔案控制代碼數量

SOCKET控制代碼洩露帶來的記憶體災難
https://www.cnblogs.com/koangel/p/5948264.html

題外篇:

Ubuntu

https://www.cnblogs.com/rayoo/p/10927572.html

替換軟體源:

mv sources.list sources.list_bak
echo “deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse” > sources.list
sudo apt-get update
sudo apt-get upgrade

安裝網路工具包:
apt install net-tools

案例

案例1

docker環境檢查佔用cpu飆升的異常java服務
1.docker status 命令檢視服務資源佔用情況 獲取cpu異常的容器id 60a01eab867b
2.docker exec -it 60a01eab867b /bin/bash 命令進入容器
3.top 命令檢視該容器執行緒佔用最高的程序PID 1
4.ps -mp 1 -o THREAD,tid,time 命令獲取到1這個程序下面所有執行緒,通過檢視%CPU找到最耗費CPU的執行緒TID 112(或者使用命令 top -Hp 1)
5.printf ‘%x’ 112 命令轉換成對應的16進位制PID 70(112為上一步中獲取到的執行緒TID )
6.jstack 1 | grep 70 -A 30 命令檢視異常資訊 注意:1是一開始獲取的程序PID,而70則是這個程序下面最耗費CPU的執行緒TID
7.jstack 1>stack.txt 命令,將該消耗程序的執行緒相關資訊匯出到stack.text檔案中,開啟這個檔案檢視每個執行緒的具體狀態然後分析程式碼異常

案例2

血坑之路:
jmap -histo:live id 會觸發full gc,要命!!!

線上配置

JVM version is 25.212-b04
Non-default VM flags: -XX:CICompilerCount=3 -XX:CMSInitiatingOccupancyFraction=70
-XX:InitialHeapSize=10737418240 -XX:MaxHeapSize=10737418240 -XX:MaxNewSize=3579117568
-XX:MaxTenuringThreshold=6 -XX:MinHeapDeltaBytes=196608 -XX:NewRatio=2 -XX:NewSize=3579117568
-XX:OldPLABSize=16 -XX:OldSize=7158300672 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC

Command line: -Xms10240m -Xmx10240m -XX:NewRatio=2 -XX:CMSInitiatingOccupancyFraction=70
-javaagent:/data/agent/skywalking-agent.jar -Dspring.profiles.active=prod
-Dakka.config.path=classpath:akka-cluster-dns.conf -Duser.timezone=Asia/Shanghai