JVM 监控分析工具
文中案例均基于JDK8
# Reference
# 第三方工具
- arthas (opens new window) 阿里开源的Java诊断利器
- perfma (opens new window) 国内jvm在线分析平台
- GCViewer (opens new window) 图形化gc日志分析工具
- GCeasy (opens new window) 在线gc日志分析工具
# JDK自带工具
# jps
官方参考文档:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jps.html (opens new window)
查看java进程ID,同样可以查看远程服务的java进程
$ jps --help
illegal argument: --help
usage: jps [-help]
jps [-q] [-mlvV] [<hostid>]
Definitions:
<hostid>: <hostname>[:<port>]
# 查看java进程ID
$ jps
19559 hello.jar
2151 world.jar
# 仅显示进程号
$ jps -q
48997
38406
# 查看java进程和main方法接收的参数
$ jps -m
19559 springbootapp.jar --spring.profiles.active=test --server.port=8080
# 查看java进程启动时的jvm参数
$ jps -v
48997 hello.jar -Dfile.encoding=utf8 -Xms1g -Xmx1g -XX:InitialBootClassLoaderMetaspaceSize=64M -XX:MaxMetaspaceSize=256M -XX:+DisableExplicitGC -XX:+UseG1GC -XX:MaxGCPauseMillis=100
# 查看java进程和执行的jar文件或者主类完整路径
$ jps -l
48997 /home/fengjx/demo/app.jar
38406 com.fengjx.app.ServerBootApp
# 不常用,查看通过flag文件传递到jvm中的参数
$ jps -V
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# jstat
官方参考文档:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html (opens new window)
jstat -options
查看jstat可以查询哪些数据
$ jstat -options
-class # 显示类装载、卸载数量、总空间和类装载耗时
-compiler # 显示JIT编译器编译过程统计信息
-gc # 显示java堆情况,包括Eden、Survivor、老年代、永久代(元空间)容量和GC合计信息
-gccapacity # 显示内容和-gc基本相同,主要关注各区域的最大、最小空间
-gcutil # 显示内容和-gc基本相同,主要关注已使用空间百分比
-gccause # 与-gcutil相同,但是会额外输出上一次GC产生原因
-gcmetacapacity # 显示元空间使用的最大、最小空间
-gcnew # 显示新生代GC状况
-gcnewcapacity # 显示内容和-gcnew基本相同,主要关注使用到的最大、最小空间
-gcold # 显示老年代GC状况
-gcoldcapacity # 显示内容和-gcold基本相同,主要关注使用到的最大、最小空间
-printcompilation # 显示已经被JIT编译的方法
2
3
4
5
6
7
8
9
10
11
12
13
# gcutil: 虚拟机统计信息监控工具
# 15200是进程号,1s表示每隔1秒输出一次,可以指定count,在执行count次数后退出
# jstat -gcutil <pid> <interval> <count>
jstat -gcutil 15200 1s
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 66.05 28.80 93.85 24.03 93.78 45401 1731.240 12 22.165 1753.405
0.00 66.05 51.80 93.85 24.03 93.78 45401 1731.240 12 22.165 1753.405
0.00 66.05 62.20 93.85 24.03 93.78 45401 1731.240 12 22.165 1753.405
2
3
4
5
6
7
- S0: S0当前使用率 - Survivor space 0 utilization as a percentage of the space's current capacity.
- S1: S1当前使用率 - Survivor space 1 utilization as a percentage of the space's current capacity.
- E: Eden当前使用率 - Eden space utilization as a percentage of the space's current capacity.
- O: 老年代当前使用率 - Old space utilization as a percentage of the space's current capacity.
- M: 元空间当前使用率 - Metaspace utilization as a percentage of the space's current capacity.
- CCS: 压缩类空间使用率 - Compressed class space utilization as a percentage.
- YGC: Young GC发生次数 - Number of young generation GC events.
- YGCT: Young GC总耗时 - Young generation garbage collection time.
- FGC: Full GC发生次数 - Number of full GC events.
- FGCT: Full GC总耗时 - Full garbage collection time.
- GCT: GC总耗时 - Total garbage collection time.
# jinfo: java配置信息查看工具
官方参考文档:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jinfo.html (opens new window)
# 格式:jinfo [option] pid
# 打印java进程参数信息,包括系统参数和jvm参数
$ jinfo 19205
Attaching to process ID 19205, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.161-b12
Java System Properties:
java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.161-b12
sun.boot.library.path = /home/fengjx/app/jdk1.8.0_161/jre/lib/amd64
java.protocol.handler.pkgs = org.springframework.boot.loader
java.vendor.url = http://java.oracle.com/
java.vm.vendor = Oracle Corporation
path.separator = :
file.encoding.pkg = sun.io
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
...
...
VM Flags:
Non-default VM flags: -XX:CICompilerCount=15 -XX:ConcGCThreads=6 -XX:G1HeapRegionSize=1048576 -XX:GCLogFileSize=10485760 -XX:InitialBootClassLoaderMetaspaceSize=67108864 -XX:InitialHeapSize=1073741824 -XX:MarkStackSize=4194304 -XX:MaxGCPauseMillis=200 -XX:MaxHeapSize=1073741824 -XX:MaxMetaspaceSize=268435456 -XX:MaxNewSize=643825664 -XX:MinHeapDeltaBytes=1048576 -XX:NumberOfGCLogFiles=3 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseG1GC -XX:+UseGCLogFileRotation
Command line: -Xms1g -Xmx1g -XX:InitialBootClassLoaderMetaspaceSize=64M -XX:MaxMetaspaceSize=256M -XX:+DisableExplicitGC -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Xloggc:/home/fengjx/logs/app/gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=3 -XX:GCLogFileSize=10M -DlogFile.dir=/home/fengjx/logs/app
# 查看是否使用了G1GC
$ jinfo -flag UseG1GC 19205
-XX:+UseG1GC
# 查看期望GC停顿时间
$ jinfo -flag MaxGCPauseMillis 19205
-XX:MaxGCPauseMillis=200
# 在不重启进程的情况下动态调整JVM参数
# jinfo -flag [+|-]<name> $pid 修改bool类型参数
# jinfo -flag <name>=<value> $pid 修改制定参数值
# 动态参数调整有限制,只有下面这些参数才可以动态调整
$ java -XX:+PrintFlagsFinal -version | grep manageable
intx CMSAbortablePrecleanWaitMillis = 100 {manageable}
intx CMSTriggerInterval = -1 {manageable}
intx CMSWaitDuration = 2000 {manageable}
bool HeapDumpAfterFullGC = false {manageable}
bool HeapDumpBeforeFullGC = false {manageable}
bool HeapDumpOnOutOfMemoryError = false {manageable}
ccstr HeapDumpPath = {manageable}
uintx MaxHeapFreeRatio = 100 {manageable}
uintx MinHeapFreeRatio = 0 {manageable}
bool PrintClassHistogram = false {manageable}
bool PrintClassHistogramAfterFullGC = false {manageable}
bool PrintClassHistogramBeforeFullGC = false {manageable}
bool PrintConcurrentLocks = false {manageable}
bool PrintGC = false {manageable}
bool PrintGCDateStamps = false {manageable}
bool PrintGCDetails = false {manageable}
bool PrintGCID = false {manageable}
bool PrintGCTimeStamps = false {manageable}
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)
# 动态修改打印gc触发时间
$ jinfo -flag +PrintGCDateStamps 48997
# 动态修改java堆dump文件输出路径
jinfo -flag HeapDumpPath=/home/fengjx/app/logs 48997
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# jmap: java内存快照监控工具
官方参考文档:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jmap.html (opens new window)
命令格式:jmap [ option ] pid
$ jmap -h
Usage:
jmap [option] <pid>
(to connect to running process)
jmap [option] <executable <core>
(to connect to a core file)
jmap [option] [server_id@]<remote server IP or hostname>
(to connect to remote debug server)
where <option> is one of:
<none> to print same info as Solaris pmap
-heap to print java heap summary
-histo[:live] to print histogram of java object heap; if the "live"
suboption is specified, only count live objects
-clstats to print class loader statistics
-finalizerinfo to print information on objects awaiting finalization
-dump:<dump-options> to dump java heap in hprof binary format
dump-options:
live dump only live objects; if not specified,
all objects in the heap are dumped.
format=b binary format
file=<file> dump heap to <file>
Example: jmap -dump:live,format=b,file=heap.bin <pid>
-F force. Use with -dump:<dump-options> <pid> or -histo
to force a heap dump or histogram when <pid> does not
respond. The "live" suboption is not supported
in this mode.
-h | -help to print this help message
-J<flag> to pass <flag> directly to the runtime system
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
选项 | 作用 | 说明 |
---|---|---|
-dump | 生成java堆快照 | 格式:-dump:[live,]format=b,file=<filename> $pid live表示是否只dump出存活对象 eg: jmap -dump:live,format=b,file=dump.bin 1349 |
-histo | 显示堆中对象统计信息:类、实例数量、合计容量 | 格式:-histo[:live] $pid live表示是否只dump出存活对象 eg: jmap -histo:live 1349(通常输出的内容太多,可以加 | head -10 ,只看前10行) |
-heap | 显示java堆详细信息:使用哪种回收器、参数配置、分代情况等 | 只在Linux / Solaris平台有效 |
-finalizerinfo | 显示在F-Queue中等待Finalizer线程执行finalize方法的对象 | 只在Linux / Solaris平台有效 |
-permstat | 以ClassLoader为统计口径显示永久代内存状态 | 只在Linux / Solaris平台有效 |
-F | 当虚拟机进程对 -dump 选项没有响应时,可以使用这个选项强制生成dump快照 | 只在Linux / Solaris平台有效 |
输出java进程存活对象快照,快照文件可以用jdk自带的jhat、VisualVM和MAT (Memory Analyzer Tool)进行分析
$ jmap -dump:live,format=b,file=dump.bin 997 Dumping heap to /home/app/logs/jvm/dump.bin ... Heap dump file created
1
2
3输出各对象内存占用信息top n
$ jmap -histo:live 997 | head -10 num #instances #bytes class name ---------------------------------------------- 1: 81758 11251848 [C 2: 80423 1930152 java.lang.String 3: 44951 1438432 java.util.concurrent.ConcurrentHashMap$Node 4: 11237 1246448 java.lang.Class 5: 12979 957472 [Ljava.util.HashMap$Node; 6: 455 859568 [Ljava.util.concurrent.ConcurrentHashMap$Node; 7: 21068 842720 java.util.LinkedHashMap$Entry
1
2
3
4
5
6
7
8
9
10instances表示实例数
bytes表示占用内存大小(字节)
class name表示对象类名
- [C is a char[]
- [S is a short[]
- [I is a int[]
- [B is a byte[]
- [[I is a int[][]
[C对象一般跟String有关,String内部使用final char[]数组来保存数据
# jhat: 虚拟机堆转储快照分析工具
官方参考文档:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jhat.html (opens new window)
jhat (JVM Heap Analysis Tool)命令与jmap配合使用,来分析jmap生成的堆快照文件。jhat内置内置了一个微型http服务,可以直接在浏览器中查看dump文件分析结果。
实际工作中很少使用jhat来分析dump文件。通常是将dump文件传到其他机器,或者开发机,通过其他工具(例如:VisualVM和MAT)进行分析。
执行jhat <filename>
后,直接访问:http://localhost:7000 就能看到分析结果
$ jhat dump.bin
Reading from dump.bin...
Dump file created Wed Nov 20 22:32:37 CST 2019
Snapshot read, resolving...
Resolving 570509 objects...
Chasing references, expect 114 dots..................................................................................................................
Eliminating duplicate references..................................................................................................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.
2
3
4
5
6
7
8
9
10
# jstack: java堆栈跟踪工具
jstack (Stack Trace For Java) 命令可以生产虚拟机当前时刻的线程快照(threaddump),用来定位线程出现长时间停顿的原因。例如:线程死锁、死循环、请求外部资源(例如:IO请求)等。
命令格式:jstack [option] pid
$ jstack -h
Usage:
jstack [-l] <pid>
(to connect to running process)
jstack -F [-m] [-l] <pid>
(to connect to a hung process)
jstack [-m] [-l] <executable> <core>
(to connect to a core file)
jstack [-m] [-l] [server_id@]<remote server IP or hostname>
(to connect to a remote debug server)
Options:
-F to force a thread dump. Use when jstack <pid> does not respond (process is hung)
-m to print both java and native frames (mixed mode)
-l long listing. Prints additional information about locks
-h or -help to print this help message
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
选项 | 作用 |
---|---|
-F | 当正常输出的请求不被响应时,强制输出线程堆栈 |
-l | 出堆栈外,显示关于锁的附加信息 |
-m | 如果调用到本地方法的话,可以显示C/C++的堆栈 |
$ jstack -l 31994
2019-11-20 23:32:12
Full thread dump OpenJDK 64-Bit Server VM (11-internal+125 mixed mode):
Threads class SMR info:
_java_thread_list=0x00007fd3087b6430, length=16, elements={
0x00007fd309015000, 0x00007fd30a018800, 0x00007fd30a01b800, 0x00007fd30a01d800,
0x00007fd30885f000, 0x00007fd30a00f800, 0x00007fd309035000, 0x00007fd30a068800,
0x00007fd3088ec000, 0x00007fd3088e4800, 0x00007fd309042000, 0x00007fd3091c4800,
0x00007fd3098b4000, 0x00007fd309209000, 0x00007fd30920a000, 0x00007fd30a1ba800
}
"main" #1 prio=5 os_prio=31 cpu=847.59ms elapsed=4363.85s tid=0x00007fd309015000 nid=0x1703 in Object.wait() [0x0000700004f9c000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(java.base@11-internal/Native Method)
- waiting on <no object reference available>
at com.intellij.execution.rmi.RemoteServer.start(RemoteServer.java:89)
- waiting to re-lock in wait() <0x00000007d0174fd8> (a java.lang.Object)
at org.jetbrains.idea.maven.server.RemoteMavenServer36.main(RemoteMavenServer36.java:23)
Locked ownable synchronizers:
- None
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
通常输出的内容会比较多,可以将内容输出到文件中,通过其他工具来分析( 例如: perfma,一个国内jvm在线分析平台 (opens new window) )
jstack -l 31994 > app-31994.jstack
线程状态:
- Deadlock: 死锁
- Waiting on condition: 等待资源
- Waiting on monitor entry: 等待获取监视器
- Blocked: 阻塞
- Runnable: 执行中
- Suspended: 暂停
- TIMED_WAITING: 对象等待中
- Parked: 停止
# jcmd: 其他监控命令(jps、jstat、jmap、jstack 等)集合
jvm 监控命令的瑞士军刀,包含了大部分其他命令常用功能,且简化了很多参数
用法:jcmd ${pid} help
jcmd 94449 help
94449:
The following commands are available:
Compiler.CodeHeap_Analytics
Compiler.codecache
Compiler.codelist
Compiler.directives_add
Compiler.directives_clear
Compiler.directives_print
Compiler.directives_remove
Compiler.queue
GC.class_histogram
GC.class_stats
GC.finalizer_info
GC.heap_dump
GC.heap_info
GC.run
GC.run_finalization
JFR.check
JFR.configure
JFR.dump
JFR.start
JFR.stop
JVMTI.agent_load
JVMTI.data_dump
ManagementAgent.start
ManagementAgent.start_local
ManagementAgent.status
ManagementAgent.stop
Thread.print
VM.class_hierarchy
VM.classloader_stats
VM.classloaders
VM.command_line
VM.dynlibs
VM.flags
VM.info
VM.log
VM.metaspace
VM.native_memory
VM.print_touched_methods
VM.set_flag
VM.stringtable
VM.symboltable
VM.system_properties
VM.systemdictionary
VM.uptime
VM.version
help
For more information about a specific command use 'help <command>'.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
命令格式:jcmd ${pid} [option]
例如:jcmd 94449 GC.class_histogram
,查看 94449 java 进程类直方图