一、堆栈信息自动保存:配置jvm参数

jvm启动参数中添加如下参数:用于OOM时自动保存堆栈信息;保存GC日志信息。

-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/tmp/heapdump.hprof
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/tmp/gc-%t.log

参数

描述

-XX:+HeapDumpOnOutOfMemoryError

JVM发生OOM时,生成heap dump文件

-XX:HeapDumpPath

heap dump文件的路径

-XX:+PrintGCDetails

打印GC详细日志

-XX:+PrintGCDateStamps

GC日志中打印执行时间戳

-Xloggc

把GC日志信息记录到文件。%t :为GC日志文件添加启动时间戳后缀,格式为:YYYY-MM-DD_HH-MM-SS 

完整jvm参数推荐配置:8G物理内存

6G~8G物理内存以上推荐使用 G1 垃圾回收器

-Xms4096m 
-Xmx4096m 
-XX:MetaspaceSize=512M 
-XX:MaxDirectMemorySize=1024M
-Xss256k
-XX:+UseG1GC 
-XX:MaxGCPauseMillis=200
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/tmp/jvm/heapdump.hprof
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/tmp/jvm/gc-%t.log
-XX:+UseGCLogFileRotation 
-XX:NumberOfGCLogFiles=10
-XX:GCLogFileSize=100M
-Djava.net.preferIPv4Stack=true 
-Duser.timezone=Asia/Shanghai 
-Dfile.encoding=UTF-8

完整jvm参数推荐配置:4G物理内存

6G物理内存以下推荐使用默认垃圾回收器-XX:+UseParallelGC,即 Parallel Scavenge + Parallel Old

-Xms2048m 
-Xmx2048m 
-XX:MetaspaceSize=512M 
-XX:MaxDirectMemorySize=1024M
-Xss128k
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/tmp/jvm/heapdump.hprof
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/tmp/jvm/gc-%t.log
-XX:+UseGCLogFileRotation 
-XX:NumberOfGCLogFiles=10
-XX:GCLogFileSize=100M
-Djava.net.preferIPv4Stack=true 
-Duser.timezone=Asia/Shanghai 
-Dfile.encoding=UTF-8

二、堆栈信息手动保存

1. 栈信息手动保存:jstack

保存当前时刻的 线程栈 信息到 jstack.log 文件中(保存在当前路径下):

jstack PID号 > jstack.log

or 
// -l : 附加锁信息,可用于分析死锁,但时间较长,慎用
jstack -l PID号 > jstack.log

2. 栈信息分析

统计java.lang.Thread.State出现的次数:

grep 'java.lang.Thread.State' jstack.log  | wc -l

将线程栈文件的状态按次数排序显示:

grep -A 1 'java.lang.Thread.State' jstack.log  | grep -v 'java.lang.Thread.State' | sort | uniq -c |sort -n

3. 堆信息手动保存:jmap

保存当前的 堆信息 到heapdump.hprof文件中:

// format=b:dump文件只支持二进制格式
jmap -dump:format=b,file=heapdump.hprof pid

or 
// live:先Full GC,再dump存活对象
jmap -dump:format=b,live,file=heapdump.hprof pid

4. 堆信息分析

获取堆概要信息:

# 查看堆的概览信息,包括堆的各个参数的值,堆中新生代、年老代的内存大小、使用率等
jmap -heap PID

# 同样,如果 JVM 进程未响应命令,可以加上参数 -F 尝试,一般不需要
jmap -F -heap PID

 获取堆中的类实例统计:

# 打印堆中的对象统计信息,以占用内存的大小排序。同样,如果 JVM 未响应命令,也可以使用 -F 参数
jmap -histo PID | head -50

or

# 只统计堆中的存活对象(先进行了一次Full GC),但使用 -F 时不支持 live
jmap -histo:live PID | more

5.查看GC信息:jstat

GC统计信息:

jstat -gc pid
 
// GC统计信息,可重点关注后5个参数:YGC、YGCT、FGC、FGCT、GCT
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
13312.0 13312.0  0.0    0.0   151040.0  1290.0   229376.0   15373.1   41728.0 38916.3 5632.0 5133.5      6    0.063   3      0.225    0.288

GC详细信息实时打印:

// 1000:打印间隔,单位毫秒
jstat -gcutil pid 1000

S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
0.00   0.00   9.09  99.97  94.45  91.98   7428  282.820   175 1403.749 1686.568

三、堆栈信息分析工具

线程栈分析:GCeasy在线工具

官网地址:https://gceasy.io/

先使用命令: jstack -l PID号 > jstack.log 保存栈信息,然后将jstack.log保存到本地,最后上传到GCeasy进行分析,观察结果:

linux 打印java进程堆栈 打印jvm堆栈信息_jvm

右边有下载PDF,可将分析结果保存到本地。

VisualVM

待定。。。

jvisualvm:jdk下启动VisualVM的命令工具。

MAT:Eclipse's Memory Analysis Tool独立版

独立版MAT下载:https://www.eclipse.org/mat/downloads.php

由于最新版本1.12.0所需的最低 Java 版本是 Java 11,所以下载旧版本:https://www.eclipse.org/mat/previousReleases.php

linux 打印java进程堆栈 打印jvm堆栈信息_java_02

独立版MAT使用

左上角 File --> Open Heap Dump --> Leak  Suspects Report(泄漏可疑报告)

linux 打印java进程堆栈 打印jvm堆栈信息_jvm_03

linux 打印java进程堆栈 打印jvm堆栈信息_JVM堆栈_04

 

linux 打印java进程堆栈 打印jvm堆栈信息_jvm_05

Problem Suspect --> See stacktrace,可看到堆溢出时候的堆栈日志:

linux 打印java进程堆栈 打印jvm堆栈信息_java_06

即可定位到出现问题的代码行! 

Problem Suspect的详情页面:

Problem Suspect --> Details(Description、Shortest Paths To the Accumulation Point、Accumulated Objects in Dominator Tree等等)

Description(描述):

linux 打印java进程堆栈 打印jvm堆栈信息_linux 打印java进程堆栈_07

Shortest Paths To the Accumulation Point(从根元素到内存消耗聚集点的最短路径): 

linux 打印java进程堆栈 打印jvm堆栈信息_物理内存_08

 Accumulated Objects in Dominator Tree(内存消耗聚集对象信息):

linux 打印java进程堆栈 打印jvm堆栈信息_jvm_09