目录
-
- 前言
- 一、jps
- 二、jinfo
- 三、jmap
- 四、jstat
-
- 4.1、语法
- 4.2、常用命令
-
- [4.2.1、-class:显示加载 class 数量及所占空间](#4.2.1、-class:显示加载 class 数量及所占空间)
- 4.2.2、-compiler:显示VM实时编译的数量
- 4.2.3、-gc:显示gc的次数及时间
- 4.2.4、-gccapacity:显示VM内存中三代(young/old/perm)对象的使用和占用大小
- 4.2.5、-gcutil:统计gc信息百分比
- 4.2.6、-gccause:显示最近一次GC统计和原因
- 五、jstack
前言
当线上出现卡顿以及涉及到 Java 性能分析时,需要使用一些 Java 提供的分析工具进行问题的定位,有一系列强大的命令和工具可以帮助开发人员分析应用程序的性能瓶颈、内存使用情况和线程问题。本文会对一些常用命令和工具做说明和示例。
以下是一些常用的命令和工具汇总:
命令 | 功能描述 |
---|---|
jps |
列出当前用户启动的Java进程。 |
jinfo |
查看正在运行的Java程序的JVM参数,并且支持运行时修改个别参数 |
jmap |
生成Java应用程序的堆快照和对象的统计信息,也可以查看运行时内存占用信息 |
jstat |
用于观察Java程序的运行时信息,常用于查看GC相关的堆信息 |
jstack |
查看应用程序的线程栈信息,常用于检测死锁 |
jconsole |
Java 自带的监控和管理控制台,它提供了一个图形化界面,允许您监视和管理正在运行的 Java 应用程序的性能和资源使用情况 |
jvisualvm |
Java 自带的一款功能强大的多合一故障诊断和性能监控的图形化工具 |
PS:本文使用JDK1.8
一、jps
jps
(JVM Process Status Tool)命令用于列出当前用户正在运行的 Java 进程信息,包括进程 pid 和主类名。这对于迅速了解系统上正在运行的 Java 应用程序很有帮助。
1.1、语法
bash
jps [ options ] [ hostid ]
其中,options
是可选的命令行选项,hostid
是可选的 RMI 注册表主机 ID。下面是一些常用的选项:
-
-q
:只输出进程ID,不包括类名和jar
文件名。 -
-m
:输出传递给main
方法的参数。 -
-l
:输出主类全名,或者对于jar
文件,输出jar
文件路径。 -
-v
:输出传递给jar
的参数。
1.2、示例
一般jps
常用的就两个命令,一个不带options
一个options
使用-l
,这里假设有一个真正运行的Java程序,主类为MyApp
。
示例:
- 1、查看当前用户所有的 Java 进程的进程 ID 和主类名
bash
$ jps
27308 Jps
29388 MyApp
- 2、查看当前用户所有的 Java 进程的进程 ID 和主类全名,或者
jar
路径
bash
$ jps -l
27308 sun.tools.jps.Jps
29388 com.kerwin.jvm.tools.MyApp
二、jinfo
jinfo
用于查看和修改正在运行的 Java 进程的 Java 虚拟机(JVM)参数和系统属性。通过使用 jinfo
可以动态地检查和更改 Java 应用程序的配置信息,而无需停止应用程序,常用于查看 JVM 参数的当前值。
2.1、语法
bash
jinfo [options] pid
options
是可选的命令行选项,pid 是正在运行的Java进程的进程ID,下面是一些常用的选项:
-flags
:打印指定Java进程的 JVM 参数值。-sysprops
:打印Java虚拟机的系统属性。-flag
name:打印指定名称的标志参数的值。-flag
[+|-]name:打印或设置指定名称的布尔标志参数的值。
2.2、示例
bash
jinfo [options] pid
- 1、
jinfo -flags pid
查看标志参数
bash
$ jinfo -flags 29388
Attaching to process ID 29388, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.281-b09
Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=536870912 -XX:MaxHeapSize=8573157376 -XX:MaxNewSize=2857369600 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=178782208 -XX:OldSize=358088704 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line:
- 2、
jinfo -sysprops pid
查看系统属性
bash
$ jinfo -sysprops 29388
Attaching to process ID 29388, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.281-b09
java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.281-b09
sun.boot.library.path = C:\Program Files\Java\jdk1.8.0_281\jre\bin
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
...
- 3、
jinfo -flag PrintGC pid
查看特定标志参数的值
bash
$ jinfo -flag PrintGC 29388
-XX:-PrintGC
- 4、
jinfo -flag +PrintGC pid
修改特定标志参数的值(不是所有参数都支持动态修改)
bash
$ jinfo -flag +PrintGC 29388
$ jinfo -flag PrintGC 29388
-XX:+PrintGC
三、jmap
jmap
(Java Memory Map)命令用于生成 Java 进程的内存映射信息。它提供了堆的详细信息,包括 Java 堆内存、对象统计和内存使用情况的详细信息,可以帮助开发人员分析内存泄漏、内存使用情况等问题。
3.1、语法
bash
jmap [options] pid
options
是一些可选的命令选项,pid
是 Java 程序的进程 ID,下面是一些常用的选项:
-
-heap
: 显示Java堆内存使用情况。 -
-histo
: 显示Java堆内存中的对象统计信息。 -
-dump:<format>=<file>
: 将堆内存转储到文件,其中为转储格式(如b, c, hprof),为目标文件名。 -
-finalizerinfo
: 显示等待终结者队列中的对象。 -
-F
: 在无法连接到进程时,强制执行转储操作。
3.2、示例
- 1、
jmap -heap pid
查看 Java 堆内存信息和使用信息
bash
$ jmap -heap 29388
...
Parallel GC with 6 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 8573157376 (8176.0MB)
NewSize = 178782208 (170.5MB)
MaxNewSize = 2857369600 (2725.0MB)
OldSize = 358088704 (341.5MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
...
From Space:
...
To Space:
...
PS Old Generation
...
- 2、使用
jmap
命令生成堆内存转储文件
bash
jmap -dump:format=b,file=heapdump.hprof 29388
通过这个命令会生成一个heapdump.hprof转储文件到当前目录,可以使用jvisualvm
或者IDEA
直接打开,个人推荐使用IDEA
直接打开,将文件拖拽到IDEA
即可。
注意事项:
- 使用
jmap
命令时,建议在测试或开发环境中进行,避免在生产环境中使用,因为生成堆内存转储文件可能会影响应用程序的性能。 jmap
命令可能需要JVM的调试权限,因此确保您有足够的权限来运行该命令。- 转储文件可能会相当大,特别是在内存使用量较大的情况下。确保您有足够的磁盘空间来存储转储文件。
四、jstat
jstat
命令监视 Java 虚拟机(JVM)的各种统计信息
4.1、语法
bash
# jstat <-命令选项> [-t] [-h<lines>] <pid> [<间隔时间/毫秒> [查询次数]]
jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
-option
: 参数选项。-t
: 可以在打印的列加上 Timestamp 列,用于显示系统运行的时间。-h
: 可以在周期性数据输出的时候,指定输出多少行以后输出一次表头。vmid
: Virtual Machine ID(进程的 pid)。interval
: 执行每次的间隔时间,单位为毫秒。count
: 用于指定输出多少次记录,缺省则会一直打印。
4.2、常用命令
4.2.1、-class:显示加载 class 数量及所占空间
bash
$ jstat -class 29388
Loaded Bytes Unloaded Bytes Time
481 985.9 0 0.0 0.08
Loaded
:加载类的数量Bytes
:加载类的size,单位为ByteUnloaded
:卸载类的数目Bytes
:卸载类的size,单位为ByteTime
:加载与卸载类花费的时间
4.2.2、-compiler:显示VM实时编译的数量
bash
$ jstat -compiler 29388
Compiled Failed Invalid Time FailedType FailedMethod
126 0 0 0.15 0
Compiled
:编译任务执行数量Failed
:编译任务执行失败数量Invalid
:编译任务执行失效数量Time
:编译任务消耗时间FailedType
:最后一个编译失败任务的类型FailedMethod
:最后一个编译失败任务所在的类及方法
4.2.3、-gc:显示gc的次数及时间
bash
$ jstat -gc 29388
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
21504.0 21504.0 0.0 0.0 131584.0 10526.8 349696.0 0.0 4480.0 788.1 384.0 76.6 0 0.000 0 0.000 0.000
- S0C:年轻代中第一个survivor(幸存区)的容量 (字节)
- S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
- S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
- S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
- EC:年轻代中Eden(伊甸园)的容量 (字节)
- EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)
- OC:老年代的容量 (字节)
- OU:老年代目前已使用空间 (字节)
- MC:metaspace(元空间)的容量 (字节)
- MU:metaspace(元空间)目前已使用空间 (字节)
- CCSC:当前压缩类空间的容量 (字节)
- CCSU:当前压缩类空间目前已使用空间 (字节)
- YGC:从应用程序启动到采样时年轻代中gc次数
- YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
- FGC:从应用程序启动到采样时老年代(全gc)gc次数
- FGCT:从应用程序启动到采样时老年代(全gc)gc所用时间(s)
- GCT:从应用程序启动到采样时gc用的总时间(s)
4.2.4、-gccapacity:显示VM内存中三代(young/old/perm)对象的使用和占用大小
bash
$ jstat -gccapacity 29388
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
174592.0 2790400.0 174592.0 21504.0 21504.0 131584.0 349696.0 5581824.0 349696.0 349696.0 0.0 1056768.0 4480.0 0.0 1048576.0 384.0 0 0
- NGCMN:年轻代(young)中初始化(最小)的大小(字节)
- NGCMX:年轻代(young)的最大容量 (字节)
- NGC:年轻代(young)中当前的容量 (字节)
- S0C:年轻代中第一个survivor(幸存区)的容量 (字节)
- S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
- EC:年轻代中Eden(伊甸园)的容量 (字节)
- OGCMN:老年代中初始化(最小)的容量大小 (字节)
- OGCMX:老年代的最大容量(字节)
- OGC:老年代当前新生成的容量 (字节)
- OC:老年代的容量 (字节)
- MCMN:metaspace(元空间)中初始化(最小)的大小 (字节)
- MCMX:metaspace(元空间)的最大容量 (字节)
- MC:metaspace(元空间)当前新生成的容量 (字节)
- CCSMN:最小压缩类空间大小
- CCSMX:最大压缩类空间大小
- CCSC:当前压缩类空间大小
- YGC:从应用程序启动到采样时年轻代中gc次数
- FGC:从应用程序启动到采样时老年代(全gc)gc次数
4.2.5、-gcutil:统计gc信息百分比
bash
$ jstat -gcutil 29388
jstat -gcutil 29388
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 0.00 8.00 0.00 17.59 19.94 0 0.000 0 0.000 0.000
- S0:年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
- S1:年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
- E:年轻代中Eden(伊甸园)已使用的占当前容量百分比
- O:old代已使用的占当前容量百分比
- M:元数据区已使用的占当前容量百分比
- CCS:压缩类空间已使用的占当前容量百分比
- YGC :从应用程序启动到采样时年轻代中gc次数
- YGCT :从应用程序启动到采样时年轻代中gc所用时间(s)
- FGC :从应用程序启动到采样时old代(全gc)gc次数
- FGCT :从应用程序启动到采样时old代(全gc)gc所用时间(s)
- GCT:从应用程序启动到采样时gc用的总时间(s)
4.2.6、-gccause:显示最近一次GC统计和原因
bash
$ jstat -gccause 29388
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC
0.00 0.00 8.00 0.00 17.59 19.94 0 0.000 0 0.000 0.000 No GC No GC
- LGCC:最后一次GC原因
- GCC:当前GC原因(No GC 为当前没有执行GC)
五、jstack
jstack
是用于输出Java应用程序的线程栈信息,常用来查看线程是否有死锁,以及CPU飙高问题定位。
5.1、语法
bash
$ jstack [ options ] pid
options
是命令选项,pid
是目标 Java 进程的进程 ID。以下是一些常用的命令选项:
-
-F
:强制生成线程堆栈,即使Java进程没有响应。 -
-m
:除了线程堆栈,还包括每个线程的本地(本地方法)信息。 -
-l
:除了线程堆栈,还包括锁信息。 -
-h
:显示帮助信息。
5.2、示例
这里模拟一个死锁例子
java
public class DeadLockMain {
private static Object A = new Object();
private static Object B = new Object();
public void deadLock() {
Thread t1 = new Thread(() -> {
synchronized (A) {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
synchronized (B) {
System.out.println("thread1");
}
}
});
Thread t2 = new Thread(() -> {
synchronized (B) {
synchronized (A) {
System.out.println("thead2");
}
}
});
t1.start();
t2.start();
}
public static void main(String[] args) {
new DeadLockMain().deadLock();
}
}
上述代码是一个简单的会发生死锁的例子,两个线程分别持有A和B,并分别请求B和A,导致死锁产生。使用jstack
打印上述进程的线程栈信息,如果出现死锁信息会在最下面输出一个Found one Java-level deadlock
信息,部分输出如下:
java
...
$ jstack 14280
2024-02-20 17:28:52
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.281-b09 mixed mode):
"DestroyJavaVM" #15 prio=5 os_prio=0 tid=0x0000012b0878d800 nid=0x445c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Thread-1" #14 prio=5 os_prio=0 tid=0x0000012b2e3ec800 nid=0x274c waiting for monitor entry [0x00000015e25ff000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.kerwin.jvm.tools.DeadLockMain.lambda$deadLock$1(DeadLockMain.java:25)
- waiting to lock <0x0000000715ce6d70> (a java.lang.Object)
- locked <0x0000000715ce6d80> (a java.lang.Object)
at com.kerwin.jvm.tools.DeadLockMain$$Lambda$2/1711574013.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Thread-0" #13 prio=5 os_prio=0 tid=0x0000012b2e3ec000 nid=0x405c waiting for monitor entry [0x00000015e24ff000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.kerwin.jvm.tools.DeadLockMain.lambda$deadLock$0(DeadLockMain.java:18)
- waiting to lock <0x0000000715ce6d80> (a java.lang.Object)
- locked <0x0000000715ce6d70> (a java.lang.Object)
at com.kerwin.jvm.tools.DeadLockMain$$Lambda$1/754666084.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x0000012b2d19c3a8 (object 0x0000000715ce6d70, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x0000012b2d1a0448 (object 0x0000000715ce6d80, a java.lang.Object),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at com.kerwin.jvm.tools.DeadLockMain.lambda$deadLock$1(DeadLockMain.java:25)
- waiting to lock <0x0000000715ce6d70> (a java.lang.Object)
- locked <0x0000000715ce6d80> (a java.lang.Object)
at com.kerwin.jvm.tools.DeadLockMain$$Lambda$2/1711574013.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Thread-0":
at com.kerwin.jvm.tools.DeadLockMain.lambda$deadLock$0(DeadLockMain.java:18)
- waiting to lock <0x0000000715ce6d80> (a java.lang.Object)
- locked <0x0000000715ce6d70> (a java.lang.Object)
at com.kerwin.jvm.tools.DeadLockMain$$Lambda$1/754666084.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.