一、前言
Java虚拟机(JVM)是Java程序运行的基础设施,它负责将Java字节码转换为本地机器代码并执行。在开发过程中,我们经常需要使用一些命令来监控和管理JVM的性能和状态。本文将详细介绍6个常用的JVM命令:jps、jstat、jmap、jhat、jstack和jinfo。
二、命令:jps
jps 命令用于列出当前系统中所有正在运行的Java进程及其主类名。它可以帮助我们快速找到我们需要调试或监控的Java进程。
命令格式:
jps [options] [hostid]
option参数:
-
-l : 输出主类全名或jar路径
-
-q : 只输出LVMID
-
-m : 输出JVM启动时传递给main()的参数
-
-v : 输出JVM启动时显示指定的JVM参数
使用示例:
bash
[root@hope ~]# jps -v
11072 Jps -Denv.class.path=.:/home/jdk-11.0.12/lib:/home/jdk-11.0.12/jre/lib: -Dapplication.home=/home/jdk-11.0.12 -Xms8m -Djdk.module.main=jdk.jcmd
27219 Elasticsearch -Xshare:auto -Des.networkaddress.cache.ttl=60 -Des.networkaddress.cache.negative.ttl=10 -XX:+AlwaysPreTouch -Xss1m -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djna.nosys=true -XX:-OmitStackTraceInFastThrow -Dio.netty.noUnsafe=true -Dio.netty.noKeySetOptimization=true -Dio.netty.recycler.maxCapacityPerThread=0 -Dio.netty.allocator.numDirectArenas=0 -Dlog4j.shutdownHookEnabled=false -Dlog4j2.disable.jmx=true -Djava.locale.providers=SPI,COMPAT -Xms1g -Xmx1g -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -Djava.io.tmpdir=/tmp/elasticsearch-13871375846251346330 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=data -XX:ErrorFile=logs/hs_err_pid%p.log -Xlog:gc*,gc+age=trace,safepoint:file=logs/gc.log:utctime,pid,tags:filecount=32,filesize=64m -XX:MaxDirectMemorySize=536870912 -Des.path.home=/usr/local/elasticsearch-7.9.3 -Des.path.conf=/usr/local/elasticsearch-7.9.3/config -Des.distribution.flavor=default -Des.distribution.type=tar -Des.bundled_jdk=true
三、命令:jstat
jstat 命令用于收集和报告关于Java虚拟机(JVM)的各种统计信息。这些信息可以帮助我们了解JVM的性能状况,例如垃圾回收情况、内存使用情况等。
命令格式:
jstat 【options】 <PID> 【interval】 【count】
命令参数说明:
-
Options,一般使用 -gcutil 或 -gc 查看gc 情况
-
pid,当前运行的 java进程号
-
interval,间隔时间,单位为秒或者毫秒
-
count,打印次数,如果缺省则打印无数次
Options 参数如下:
-
-gc:统计 jdk gc时 heap信息,以使用空间字节数表示
-
-gcutil:统计 gc时, heap情况,以使用空间的百分比表示
-
-class:统计 class loader行为信息
-
-compile:统计编译行为信息
-
-gccapacity:统计不同 generations(新生代,老年代,持久代)的 heap容量情况
-
-gccause:统计引起 gc的事件
-
-gcnew:统计 gc时,新生代的情况
-
-gcnewcapacity:统计 gc时,新生代 heap容量
-
-gcold:统计 gc时,老年代的情况
-
-gcoldcapacity:统计 gc时,老年代 heap容量
-
-gcpermcapacity:统计 gc时, permanent区 heap容量
使用示例1:
jstat -gc 15 5000 5
每5秒一次显示进程号为15的java进程的GC情况,每5S生成异常,一共生成5次。
我可以计算出如下核心数据:
-
第一个幸存区的大小S0C:300M
-
第二个幸存区的大小S1C:300M
-
伊甸园区的大小EC:2400M
-
老年代大小OC:5000M
-
方法区大小MC:236M
-
年轻代垃圾回收消耗时间YGCT:531.164(单位?)
-
老年代垃圾回收消耗时间FGCT:6.874(单位?)
我们再看输出的GC日志:
bash
Heap before GC invocations=6641 (full 10):
par new generation total 2764800K, used 2492979K [0x00000005cc000000, 0x0000000687800000, 0x0000000687800000)
eden space 2457600K, 100% used [0x00000005cc000000, 0x0000000662000000, 0x0000000662000000)
from space 307200K, 11% used [0x0000000674c00000, 0x0000000676e8cc90, 0x0000000687800000)
to space 307200K, 0% used [0x0000000662000000, 0x0000000662000000, 0x0000000674c00000)
concurrent mark-sweep generation total 5120000K, used 3462278K [0x0000000687800000, 0x00000007c0000000, 0x00000007c0000000)
Metaspace used 209218K, capacity 229352K, committed 241360K, reserved 1265664K
class space used 20538K, capacity 24038K, committed 26120K, reserved 1048576K
343501.719: [GC (Allocation Failure) 343501.719: [ParNew: 2492979K->24333K(2764800K), 0.0261186 secs] 5955257K->3486700K(7884800K), 0.0262698 secs] [Times: user=0.05 sys=0.01, real=0.03 secs]
可以计算出如下核心数据:
-
第一个幸存区的大小S0C:300M
-
第二个幸存区的大小S1C:300M
-
伊甸园区的大小EC:2400M
-
老年代大小OC:从这里计算不出来
-
方法区大小MC:从这里计算不出来
-
GC耗时:30ms
配置的JAVA_OPTS参数如下:
-Xmx8000M -Xms8000M -Xmn3000M -XX:PermSize=1000M -XX:MaxPermSize=1000M -Xss256K -XX:+DisableExplicitGC -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=69 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:/home/work/logs/applogs/gc.log -javaagent:/home/work/app/prometheus/jmx_prometheus_javaagent-0.12.0.jar=3010:/home/work/app/prometheus/jmx-exporter.yml
使用示例2:
jstat -gccapacity 15
同-gc,不过还会输出Java堆各区域使用到的最大、最小空间
bash
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
819200.0 819200.0 819200.0 273024.0 273024.0 273152.0 5324800.0 5324800.0 5324800.0 5324800.0 0.0 1251328.0 223560.0 0.0 1048576.0 22716.0 174 8
bash
NGCMN Minimum new generation capacity (KB).
NGCMX Maximum new generation capacity (KB).
NGC Current new generation capacity (KB).
S0C Current survivor space 0 capacity (KB).
S1C Current survivor space 1 capacity (KB).
EC Current eden space capacity (KB).
OGCMN Minimum old generation capacity (KB).
OGCMX Maximum old generation capacity (KB).
OGC Current old generation capacity (KB).
OC Current old space capacity (KB).
PGCMN Minimum permanent generation capacity (KB).
PGCMX Maximum Permanent generation capacity (KB).
PGC Current Permanent generation capacity (KB).
PC Current Permanent space capacity (KB).
YGC Number of Young generation GC Events.
FGC Number of Full GC Events.
四、命令:jmap
jmap命令用于生成Java堆内存快照文件(heap dump)。这些文件可以用于分析内存泄漏问题,或者进行性能调优。
命令格式:
jmap 【options】 <pid>
options参数解释 :
-
no options 如果使用不带选项参数的jmap打印共享对象映射, 将会打印目标虚拟机中加载的每个对象的起始地址、映射大小及共享对象文件的路径全称。(很占资源, 一般不会使用)
-
-heap:打印java heap 摘要
-
-histo[:live] :打印堆中的java对象统计信息
-
-clstats :打印类加载器统计信息
-
-finalizerinfo:打印在f-queue中等待执行finalizer方法的对象
-
-dump:生成java堆的dump文件, dump-options:
-
live :只转储存活的对象,如果没有指定则转储所有对象
-
format=b:二进制格式
-
file=[Path] :将文件转储到指定文件中
使用示例1:
将java堆中存活的对象信息转储到/dump.bin文件中
jmap -dump:live,format=b,file=/dump.bin 0813
我们来看一下堆信息:
jmap -heap 0813
输出:
bash
Attaching to process ID 11666, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.25-b02
using thread-local object allocation.
Parallel GC with 4 thread(s)
Heap Configuration: //堆内存初始化配置
MinHeapFreeRatio = 0 //对应jvm启动参数-XX:MinHeapFreeRatio设置JVM堆最小空闲比率(default 40)
MaxHeapFreeRatio = 100 //对应jvm启动参数 -XX:MaxHeapFreeRatio设置JVM堆最大空闲比率(default 70)
MaxHeapSize= 1073741824 (1024.0MB) //对应jvm启动参数-XX:MaxHeapSize=设置JVM堆的最大大小
NewSize = 22020096 (21.0MB) //对应jvm启动参数-XX:NewSize=设置JVM堆的新生代的默认大小
MaxNewSize = 357564416 (341.0MB) //对应jvm启动参数-XX:MaxNewSize=设置JVM堆的新生代的最大大小
OldSize = 45088768 (43.0MB) //对应jvm启动参数-XX:OldSize=<value>:设置JVM堆的老年代的大小
NewRatio = 2 //对应jvm启动参数-XX:NewRatio=:新生代和老生代的大小比率
SurvivorRatio = 8 //对应jvm启动参数-XX:SurvivorRatio=设置新生代中Eden区与Survivor区的大小比值
MetaspaceSize = 21807104 (20.796875MB) // 元数据区大小
CompressedClassSpaceSize = 1073741824 (1024.0MB) //类压缩空间大小
MaxMetaspaceSize = 17592186044415 MB //元数据区最大大小
G1HeapRegionSize = 0 (0.0MB) //G1垃圾收集器每个Region大小
Heap Usage: //堆内存使用情况
PS Young Generation
Eden Space: //Eden区内存分布
capacity = 17825792 (17.0MB) //Eden区总容量
used = 12704088 (12.115562438964844MB) //Eden区已使用
free = 5121704 (4.884437561035156MB) //Eden区剩余容量
71.26801434685203% used //Eden区使用比率
From Space: //其中一个Survivor区的内存分布
capacity = 2097152 (2.0MB)
used = 1703936 (1.625MB)
free = 393216 (0.375MB)
81.25% used
To Space: //另一个Survivor区的内存分布
capacity = 2097152 (2.0MB)
used = 0 (0.0MB)
free = 2097152 (2.0MB)
0.0% used
PS Old Generation
capacity = 52428800 (50.0MB) //老年代容量
used = 28325712 (27.013504028320312MB) //老年代已使用
free = 24103088 (22.986495971679688MB) //老年代空闲
54.027008056640625% used //老年代使用比率
15884 interned Strings occupying 2075304 bytes.
输出存活对象信息 :
jmap -histo:live 0813 | more
使用示例2:
jmap -histo:live 10 | more
打印堆的对象统计,包括对象数、内存大小等等 (因为在dump:live前会进行full gc,如果带上live则只统计活对象,因此不加live的堆大小要大于加live堆的大小 ),仅打印前10行。
bash
num #instances #bytes class name
----------------------------------------------
1: 938552 113143448 [C
2: 983711 31478752 java.util.HashMap$Node
3: 930339 22328136 java.lang.String
4: 61854 21628224 [B
5: 215981 19006328 java.lang.reflect.Method
6: 200183 18164992 [Ljava.lang.Object;
7: 121341 16297048 [Ljava.util.HashMap$Node;
8: 511306 12919376 [Ljava.lang.String;
9: 169168 9391000 [I
10: 165488 6619520 java.util.LinkedHashMap$Entry
11: 131563 6315024 org.hibernate.hql.internal.ast.tree.Node
12: 122202 5865696 java.util.HashMap
13: 320105 5121680 java.lang.Integer
14: 204087 4898088 java.util.ArrayList
15: 138888 4444416 java.util.concurrent.ConcurrentHashMap$Node
... ...
xml class name是对象类型,说明如下:
bash
B byte
C char
D double
F float
I int
J long
Z boolean
[数组,如[I表示int[]
[L+类名 其他对象
五、命令:jhat
jhat 用来分析jmap生成dump文件的命令, jhat内置了应用服务器,可以通过网页查看dump文件分析结果,jhat一般用于离线分析。
命令格式:
jhap 【options】 【dumpfile】
option参数解释:
-
-stack false :关闭对象分配调用堆栈的跟踪
-
-refs false:关闭对象引用的跟踪
-
-port:HTTP服务器端口, 默认是7000
-
-debug:debug级别
-
-version:分析报告版本
使用示例:
jhat dump.hprof
执行结果:
可以通过Http://localhost:7000访问:
具体排查时需要结合代码,观察是否大量应该被回收的对象在一直被引用或者是否有占用内存特别大的对象无法被回收。一般情况,会down到客户端用工具来分析。
六、命令:jstack
jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。
如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。
另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。
命令格式:
jstack 【options】 【pid】
options参数解释:
-
-F :当使用jstack无响应时,强制输出线程堆栈
-
-m:同时输出java堆栈和c/c++ 堆栈信息
-
-l :除了输出堆栈信息外, 显示关于锁的附加信息
使用示例:
jstack -l 5073|more
执行结果:
七、命令:jinfo
jinfo命令用于显示Java虚拟机(JVM)的配置信息,包括系统属性、Java版本、可用的JVM选项等。这可以帮助我们了解JVM的配置和使用情况。
命令格式:
jinfo 【options】 <pid>
options参数解释:
-
no options :输出所有的系统属性和参数
-
-flag :打印指定名称的参数
-
-flag [+|-] :打开或关闭参数
-
-flag = 设置参数值
-
-flags 打印所有参数
-
-sysprops 打印系统配置
使用示例:
bash
# 查看jvm参数和系统配置
jinfo 1234
jinfo -flags 1234
jinfo -sysprops 1234
# 查看打印GC日志参数
jinfo -flag PrintGC 1234
jinfo -flag PrintGCDetail 1234
# 打开/关闭 GC日志
jinfo -flag +PrintGC 1234
jinfo -flag -PrintGCDetail 1234
# 设置或自改参数值
jinfo -flag -Xms10m 1234