在 Java 开发过程中,性能监控和问题排查是开发者经常面临的任务。JDK 提供了一系列命令行工具,帮助开发者监控 JVM 运行状态、诊断内存泄漏、线程死锁等问题。本文将详细介绍这些工具的使用方法及其应用场景。
1 JDK性能监控工具
1.1 jps:查看虚拟机进程
jps
(Java Virtual Machine Process Status Tool)是 JDK 提供的一个命令行工具,用于快速查看当前系统中正在运行的 Java 应用及其进程 ID(PID)。它的功能类似于 Linux 下的 ps
命令,但专门针对 Java 进程。通过 jps
,开发者可以快速获取 Java 进程的 PID,从而为后续使用其他 JVM 工具(如 jstack
、jmap
等)进行诊断提供便利。
1.1.1 命令格式
jps [options] [hostid]
options
:可选参数,用于控制输出内容。hostid
:可选参数,用于指定远程主机的标识符(通常用于远程监控)。
命令示例
运行 jps
命令后,输出结果可能如下:
12345 MainClass
67890 AnotherApp
54321 SpringBootApp
- 每一行输出包含两部分:进程 ID(PID) 和 主类名称。
- 例如,
54321 SpringBootApp
表示 PID 为54321
的进程正在运行一个名为SpringBootApp
的 Java 应用。
1.1.2 PID 的作用
- PID(Process ID) 是操作系统分配给每个进程的唯一标识符。
- 通过 PID,开发者可以查看进程的详细信息,或者使用
kill
命令终止进程。 - 例如,强制终止 PID 为
54321
的进程:kill -9 54321
注意:
kill -9
会强制终止进程,可能导致数据丢失或应用异常退出,生产环境中需谨慎使用。
1.1.3 常用选项
选项 | 描述 |
---|---|
-q | 只输出进程 ID,忽略主类信息。 |
-l | 输出主类的全名,如果进程是通过 JAR 包启动的,则输出 JAR 文件的完整路径。 |
-m | 输出虚拟机进程启动时传递给主类 main() 方法的参数。 |
-v | 输出虚拟机进程启动时的 JVM 参数。 |
示例用法
-
查看所有 Java 进程及其主类全名:
jps -l
输出示例:
12345 com.example.MainClass 67890 /path/to/AnotherApp.jar
-
查看 Java 进程的 JVM 启动参数:
jps -v
输出示例:
12345 MainClass -Xms512m -Xmx1024m
-
只查看 Java 进程的 PID:
jps -q
输出示例:
12345 67890
1.2 jstat:查看 JVM 运行时信息
jstat
(Java Virtual Machine Statistics Monitoring Tool)是 JDK 提供的一个命令行工具,用于监控 JVM 的各种运行时状态信息。它能够提供关于垃圾回收、类加载、JIT 编译等方面的详细数据,帮助开发者分析和优化 Java 应用的性能。
1.2.1 命令格式
jstat [option vmid [interval[s|ms] [count]]]
option
:指定监控的类别,例如类加载、垃圾回收等。vmid
:目标 Java 进程的进程 ID(PID)。interval
:采样间隔时间,单位为秒(s)或毫秒(ms)。count
:采样次数。
1.2.2 主要选项
jstat
的选项主要分为三类:类加载、垃圾回收、运行期编译状况。以下是常用选项及其功能:
1. -class
:监视类加载信息
用于监控类的加载、卸载数量、总空间以及类加载所耗费的时间。
命令示例:
jstat -class -t 75952 1000 2
输出示例:
Loaded Bytes Unloaded Bytes Time
5000 10.5 MB 100 0.2 MB 1.23s
5100 10.8 MB 110 0.3 MB 1.45s
字段说明:
Loaded
:加载的类的数量。Bytes
:所有加载类占用的空间大小。Unloaded
:卸载的类的数量。Time
:类加载器所花费的时间。
2. -gc
:监视 Java 堆状况
用于监控 Java 堆的各个区域(Eden 区、Survivor 区、老年代等)的容量、已用空间以及垃圾回收的时间和次数。
命令示例:
jstat -gc 75952 1000 2
输出示例:
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
1024.0 1024.0 0.0 0.0 8192.0 1024.0 20480.0 1024.0 4480.0 2560.0 384.0 256.0 1 0.005 0 0.000 0.005
1024.0 1024.0 0.0 0.0 8192.0 2048.0 20480.0 1024.0 4480.0 2560.0 384.0 256.0 1 0.005 0 0.000 0.005
字段说明:
S0C
、S1C
:Survivor 0 区和 Survivor 1 区的当前容量(Current)。S0U
、S1U
:Survivor 0 区和 Survivor 1 区的已使用空间(Used)。EC
、EU
:Eden 区的容量和已使用空间。OC
、OU
:老年代的容量和已使用空间。MC
、MU
:元空间(Metaspace)的容量和已使用空间。YGC
、YGCT
:年轻代垃圾回收的次数和总时间。FGC
、FGCT
:老年代垃圾回收(Full GC)的次数和总时间。GCT
:垃圾回收的总时间。
3. -compiler
:监视 JIT 编译信息
用于监控 JIT(Just-In-Time)编译器编译过的方法、耗时等信息。
命令示例:
jstat -compiler 75952 1000 2
输出示例:
Compiled Failed Invalid Time FailedType FailedMethod
1000 10 5 1.23s SomeClass someMethod
1050 12 6 1.45s AnotherClass anotherMethod
字段说明:
Compiled
:编译的方法数量。Failed
:编译失败的方法数量。Invalid
:失效的编译方法数量。Time
:编译所花费的时间。
1.2.3 其他常用选项
选项 | 描述 |
---|---|
-gccapacity | 监控 Java 堆各个区域的最大、最小空间。 |
-gcutil | 监控 Java 堆各个区域的已使用空间占总空间的百分比。 |
-gccause | 与 -gcutil 功能相同,但额外输出导致上一次垃圾回收的原因。 |
-gcnew | 监控新生代垃圾回收情况。 |
-gcnewcapacity | 监控新生代的最大、最小空间。 |
-gcold | 监控老年代垃圾回收情况。 |
-gcoldcapacity | 监控老年代的最大、最小空间。 |
-printcompilation | 输出已经被 JIT 编译的方法。 |
1.3 jinfo:查看虚拟机配置
jinfo
(Configuration Info for Java)是 JDK 提供的一个命令行工具,用于查看或动态调整 JVM 的各项配置参数。它的主要功能包括:
- 查看 JVM 参数:输出当前 Java 进程的 JVM 启动参数。
- 动态修改参数:在不重启应用的情况下,调整某些 JVM 参数(仅限于支持动态修改的参数)。
1.3.1 命令格式
jinfo [option] pid
option
:可选参数,用于指定操作类型。pid
:目标 Java 进程的进程 ID。
1.3.2 常用选项
选项 | 描述 |
---|---|
-flags | 输出 JVM 的启动参数。 |
-sysprops | 输出 Java 系统属性(等同于 System.getProperties() )。 |
-flag <name> | 查看某个特定 JVM 参数的值。 |
-flag [+|-]<name> | 动态启用或禁用某个 JVM 参数。 |
1.3.3 示例用法
-
查看 JVM 启动参数:
jinfo -flags 88952
输出示例:
Attaching to process ID 88952, please wait... Debugger attached successfully. Server compiler detected. JVM version is 11.0.12+7-LTS Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4294967296 ... Command line: -Xms256m -Xmx4G
-
查看 Java 系统属性:
jinfo -sysprops 88952
输出示例:
Attaching to process ID 88952, please wait... Debugger attached successfully. Server compiler detected. JVM version is 11.0.12+7-LTS java.runtime.name = Java(TM) SE Runtime Environment java.vm.version = 11.0.12+7-LTS user.country = CN ...
-
查看特定 JVM 参数的值:
jinfo -flag MaxHeapSize 88952
输出示例:
-XX:MaxHeapSize=4294967296
-
动态修改 JVM 参数:
jinfo -flag +PrintGCDetails 88952
注意:并非所有 JVM 参数都支持动态修改,具体取决于 JVM 实现和参数类型。
1.3.4 常见问题及解决方法
问题:jinfo
命令无法执行成功,提示无法附加到进程。
可能原因:
- JDK 版本不一致:
jinfo
工具的版本与目标 Java 进程使用的 JDK 版本不一致。 - 权限不足:当前用户没有权限访问目标进程。
- JDK 版本过旧:某些旧版本 JDK 可能存在兼容性问题。
解决方法:
-
确保 JDK 版本一致:
- 使用与目标 Java 进程相同的 JDK 版本的
jinfo
工具。 - 例如,如果目标进程使用 JDK 11,则确保
jinfo
也来自 JDK 11。
- 使用与目标 Java 进程相同的 JDK 版本的
-
使用管理员权限运行:
- 在 Linux/macOS 上,尝试使用
sudo
提升权限:sudo jinfo -flags <pid>
- 在 Linux/macOS 上,尝试使用
-
升级 JDK 版本:
- 如果使用的是较旧的 JDK 版本,尝试升级到较新的稳定版本(如 JDK 11 或 JDK 17)。
示例:
# 使用 JDK 11 的 jinfo 查看进程信息
/usr/lib/jvm/jdk-11/bin/jinfo -flags 10025
1.4 jmap:导出堆快照
jmap
(Java Memory Map)是 JDK 提供的一个命令行工具,用于生成 Java 堆转储快照(heap dump),并查看堆内存的详细信息。堆转储文件包含了 JVM 堆中所有对象的信息,包括类、属性、引用等,是分析内存泄漏和优化内存使用的重要工具。
1.4.1 命令格式
jmap [option] vmid
option
:指定操作类型。vmid
:目标 Java 进程的进程 ID(PID)。
1.4.2 常用选项
选项 | 描述 |
---|---|
-dump | 生成 Java 堆转储快照(heap dump)。 |
-finalizerinfo | 显示在 F-Queue 中等待 Finalizer 线程执行 finalize 方法的对象。(仅限 Linux 平台) |
-heap | 显示 Java 堆的详细信息,包括垃圾回收器类型、参数配置、分代情况等。(仅限 Linux 平台) |
-histo | 显示堆中对象的统计信息,包括类、实例数量、占用内存大小等。 |
-F | 当目标进程对 -dump 选项无响应时,强制生成堆转储快照。(仅限 Linux 平台) |
1.4.3 示例用法
-
生成堆转储快照:
jmap -dump:format=b,file=heap.hprof 10025
format=b
:指定文件格式为二进制。file=heap.hprof
:指定输出文件名为heap.hprof
。10025
:目标 Java 进程的 PID。
说明:
- 生成的堆转储文件(
heap.hprof
)可以使用工具(如 Eclipse MAT、VisualVM)进行分析。
-
查看堆中对象统计信息:
jmap -histo 10025
输出示例:
num #instances #bytes class name --------------------------------------------- 1: 100000 10000000 java.lang.String 2: 50000 2000000 java.util.HashMap$Node 3: 30000 1200000 java.lang.Object ...
#instances
:类的实例数量。#bytes
:实例占用的内存大小。class name
:类名。
-
显示 Java 堆详细信息:
jmap -heap 10025
输出示例:
Attaching to process ID 10025, please wait... Debugger attached successfully. Server compiler detected. JVM version is 11.0.12+7-LTS using thread-local object allocation. Parallel GC with 4 thread(s) Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 4294967296 (4096.0MB) NewSize = 10485760 (10.0MB) MaxNewSize = 4294967296 (4096.0MB) OldSize = 20971520 (20.0MB) NewRatio = 2 SurvivorRatio = 8 ...
-
强制生成堆转储快照:
jmap -F -dump:format=b,file=heap.hprof 10025
- 当目标进程无响应时,使用
-F
选项强制生成堆转储。
- 当目标进程无响应时,使用
1.4.4 堆转储文件分析工具
生成的堆转储文件(如 heap.hprof
)可以使用以下工具进行分析:
-
Eclipse MAT(Memory Analyzer Tool):
- 功能强大,支持内存泄漏分析、对象依赖关系查看等。
- 下载地址:Eclipse MAT
-
VisualVM:
- JDK 自带的图形化工具,支持堆转储分析和性能监控。
- 启动命令:
jvisualvm
-
JProfiler:
- 商业工具,提供全面的性能分析和堆转储分析功能。
- 官网:JProfiler
1.5 jstack:跟踪 Java 堆栈
jstack
是 JDK 提供的一个命令行工具,用于打印 JVM 中某个进程的线程堆栈信息(通常称为 threaddump 或 javacore 文件)。它常用于诊断应用程序中的线程问题,如线程死锁、死循环或长时间等待。
1.5.1 命令格式
jstack [option] vmid
option
:可选参数,用于控制输出内容。vmid
:目标 Java 进程的进程 ID(PID)。
1.5.2 常用选项
选项 | 描述 |
---|---|
-F | 当正常输出的请求不被响应时,强制输出线程堆栈。 |
-l | 除了堆栈信息外,显示关于锁的附加信息(如持有的锁、等待的锁等)。 |
-m | 如果调用的是本地方法(Native Method),显示 C/C++ 的堆栈信息。 |
1.5.3 示例用法
-
打印线程堆栈信息:
jstack 10025
输出示例:
"main" #1 prio=5 os_prio=0 tid=0x00007f8b4c009000 nid=0x2703 waiting on condition [0x00007f8b4d0f0000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x000000076b70c4b8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199) at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285) at com.example.DeadLockDemo.lambda$main$0(DeadLockDemo.java:10) at com.example.DeadLockDemo$$Lambda$1/1096979270.run(Unknown Source) at java.lang.Thread.run(Thread.java:748)
-
打印线程堆栈信息及锁信息:
jstack -l 10025
输出示例:
"Thread-1" #12 prio=5 os_prio=0 tid=0x00007f8b4c0b8000 nid=0x2705 waiting for monitor entry [0x00007f8b4b6f0000] java.lang.Thread.State: BLOCKED (on object monitor) at com.example.DeadLockDemo.lambda$main$1(DeadLockDemo.java:25) - waiting to lock <0x000000076b70c4b8> (a java.lang.Object) - locked <0x000000076b70c4c8> (a java.lang.Object) at com.example.DeadLockDemo$$Lambda$2/1324119927.run(Unknown Source) at java.lang.Thread.run(Thread.java:748) "Thread-0" #11 prio=5 os_prio=0 tid=0x00007f8b4c0b7000 nid=0x2704 waiting for monitor entry [0x00007f8b4b7f0000] java.lang.Thread.State: BLOCKED (on object monitor) at com.example.DeadLockDemo.lambda$main$0(DeadLockDemo.java:15) - waiting to lock <0x000000076b70c4c8> (a java.lang.Object) - locked <0x000000076b70c4b8> (a java.lang.Object) at com.example.DeadLockDemo$$Lambda$1/1096979270.run(Unknown Source) at java.lang.Thread.run(Thread.java:748)
-
强制打印线程堆栈信息:
jstack -F 10025
- 当目标进程无响应时,使用
-F
选项强制输出线程堆栈。
- 当目标进程无响应时,使用
1.5.4 诊断死锁问题
以下是一个简单的死锁示例程序:
class DeadLockDemo {
private static final Object lock1 = new Object();
private static final Object lock2 = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (lock1) {
System.out.println("线程1获取到了锁1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("线程1获取到了锁2");
}
}
}).start();
new Thread(() -> {
synchronized (lock2) {
System.out.println("线程2获取到了锁2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("线程2获取到了锁1");
}
}
}).start();
}
}
运行结果:
程序运行后卡住,无法继续执行。
使用 jstack
诊断死锁:
jstack -l <pid>
输出示例:
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x00007f8b4c0b8000 (object 0x000000076b70c4b8, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x00007f8b4c0b7000 (object 0x000000076b70c4c8, a java.lang.Object),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at com.example.DeadLockDemo.lambda$main$1(DeadLockDemo.java:25)
- waiting to lock <0x000000076b70c4b8> (a java.lang.Object)
- locked <0x000000076b70c4c8> (a java.lang.Object)
at com.example.DeadLockDemo$$Lambda$2/1324119927.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Thread-0":
at com.example.DeadLockDemo.lambda$main$0(DeadLockDemo.java:15)
- waiting to lock <0x000000076b70c4c8> (a java.lang.Object)
- locked <0x000000076b70c4b8> (a java.lang.Object)
at com.example.DeadLockDemo$$Lambda$1/1096979270.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
说明:
jstack
输出了死锁的详细信息,包括哪些线程在等待哪些锁,以及锁的持有者。
1.6 jcmd:多功能命令
jcmd
是 JDK 提供的一个多功能命令行工具,集成了 jstack
、jmap
、jstat
、jinfo
等工具的功能。它能够收集堆转储、生成 JVM 和 Java 应用程序的性能数据,以及动态更改某些 Java 运行时参数。jcmd
的强大之处在于它可以通过单一命令完成多种任务,简化了 JVM 监控和诊断的操作。
1.6.1 命令格式
jcmd <pid | main class> <command ... | PerfCounter.print | -f file>
pid
:目标 Java 进程的进程 ID。main class
:目标 Java 应用的主类名。command
:要执行的操作或命令。PerfCounter.print
:打印性能计数器信息。-f file
:从文件中读取命令并执行。
1.6.2 常用功能
-
列出所有 Java 应用:
jcmd -l
输出示例:
10025 com.example.MainClass 20036 org.apache.catalina.startup.Bootstrap
-
查看支持的命令:
jcmd 10025 help
输出示例:
The following commands are available: JFR.stop JFR.start JFR.dump JFR.check VM.native_memory VM.check_commercial_features VM.unlock_commercial_features ManagementAgent.stop ManagementAgent.start_local ManagementAgent.start Thread.print GC.class_histogram GC.heap_dump GC.run_finalization GC.run VM.uptime VM.flags VM.system_properties VM.command_line VM.version help
-
查看 JVM 参数:
jcmd 10025 VM.flags
输出示例:
-XX:CICompilerCount=4 -XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4294967296 ...
-
打印线程信息:
jcmd 10025 Thread.print
输出示例:
"main" #1 prio=5 os_prio=0 tid=0x00007f8b4c009000 nid=0x2703 waiting on condition [0x00007f8b4d0f0000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x000000076b70c4b8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199) at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285) at com.example.DeadLockDemo.lambda$main$0(DeadLockDemo.java:10) at com.example.DeadLockDemo$$Lambda$1/1096979270.run(Unknown Source) at java.lang.Thread.run(Thread.java:748)
-
生成堆转储文件:
jcmd 10025 GC.heap_dump filename=heap.hprof
说明:
- 生成的堆转储文件(
heap.hprof
)可以使用工具(如 Eclipse MAT、VisualVM)进行分析。
- 生成的堆转储文件(
-
打印性能计数器信息:
jcmd 10025 PerfCounter.print
输出示例:
java.ci.totalTime=123456 java.cls.loadedClasses=5000 java.cls.unloadedClasses=100 ...
-
查看系统属性:
jcmd 10025 VM.system_properties
输出示例:
java.runtime.name=Java(TM) SE Runtime Environment java.vm.version=11.0.12+7-LTS user.country=CN ...
-
查看 JVM 启动时间:
jcmd 10025 VM.uptime
输出示例:
1234.567 seconds
1.6.3 主要选项
选项 | 描述 | 补充说明 |
---|---|---|
help | 打印帮助信息。 | 示例:jcmd help |
ManagementAgent.stop | 停止 JMX Agent。 | |
ManagementAgent.start_local | 开启本地 JMX Agent。 | |
ManagementAgent.start | 开启 JMX Agent。 | |
Thread.print | 打印线程信息,相当于 jstack 。 | 支持 -l 参数打印锁信息。 |
PerfCounter.print | 打印性能计数器信息,相当于 jstat -J-Djstat.showUnsupported=true -snap 。 | |
GC.class_histogram | 打印堆中对象统计信息,相当于 jmap -histo 。 | |
GC.heap_dump | 生成堆转储文件,相当于 jmap -dump:format=b,file=xxx.bin 。 | |
GC.run_finalization | 运行 finalize 方法,相当于 System.runFinalization() 。 | |
GC.run | 触发垃圾回收,相当于 System.gc() 。 | |
VM.uptime | 打印 JVM 启动时间,以秒为单位。 | 支持 -date 参数打印当前时间。 |
VM.flags | 打印 JVM 参数,相当于 jinfo -flags 。 | 支持 -all 参数输出全部信息。 |
VM.system_properties | 打印系统属性,相当于 jinfo -sysprops 。 | |
VM.command_line | 打印 JVM 启动命令,相当于 `jinfo -sysprops | grep command`。 |
VM.version | 打印 JVM 版本信息,相当于 `jinfo -sysprops | grep version`。 |
2 操作系统工具
除了 JDK 自带的工具,操作系统也提供了一些命令行工具,帮助开发者监控系统资源使用情况。
2.1 top:显示系统整体资源使用情况
top
是一个常用的命令行工具,用于实时监控系统的整体资源使用情况,包括 CPU、内存、进程等。它能够帮助开发者快速识别系统中占用资源较高的进程,从而进行性能分析和优化。
2.1.1 命令格式
top
- 默认情况下,
top
会实时更新显示信息,按Ctrl + C
退出。
2.1.2 输出解析
top
的输出分为两部分:统计信息和进程信息。
1. 统计信息
统计信息部分提供了系统的整体资源使用情况,主要包括以下内容:
-
进程和线程信息:
Processes: 500 total, 10 running, 490 sleeping, 2000 threads
Processes
:总进程数。running
:正在运行的进程数。sleeping
:睡眠的进程数。threads
:总线程数。
-
负载均衡和 CPU 使用率:
Load Avg: 4.02, 3.89, 3.29 CPU usage: 6.97% user, 3.54% sys, 89.47% idle
Load Avg
:过去 1 分钟、5 分钟和 15 分钟的平均系统负载。负载值大于 CPU 核心数时,表示系统相对繁忙。CPU usage
:user
:用户进程占用的 CPU 百分比。sys
:系统内核占用的 CPU 百分比。idle
:CPU 空闲百分比。
-
共享库内存使用:
SharedLibs: 100M resident, 50M data, 10M linkedit.
- 显示操作系统加载的共享库(如动态链接库)的内存使用情况。
-
内存区域使用:
MemRegions: 5000 total, 100M resident, 50M private, 200M shared.
- 显示系统内存区域的使用情况,包括代码、数据、堆、栈等。
-
物理内存使用:
PhysMem: 30G used (3018M wired), 1547M unused.
used
:已使用的物理内存。wired
:被锁定在内存中的部分(不可被交换到磁盘)。unused
:未使用的物理内存。
-
虚拟内存信息:
VM: 50G vsize, 20G framework vsize, 10G swapins, 5G swapouts.
vsize
:虚拟内存总量。swapins
:从磁盘交换到内存的数据量。swapouts
:从内存交换到磁盘的数据量。
-
网络和硬盘信息:
Networks: packets: 22655692/19G in, 19180791/11G out. Disks: 14866544/288G read, 15176739/251G written.
Networks
:网络接收和发送的数据包数量及大小。Disks
:硬盘读取和写入的次数及数据量。
2. 进程信息
进程信息部分列出了系统中各个进程的资源使用情况,主要字段包括:
字段 | 描述 |
---|---|
PID | 进程 ID,是操作系统分配给进程的唯一标识符。 |
COMMAND | 进程的命令名或命令行。 |
%CPU | 进程占用的 CPU 使用率。 |
TIME | 进程使用的 CPU 时间总计,单位为 1/100 秒。 |
MEM | 进程使用的物理内存和虚拟内存大小,单位为 KB。 |
示例:
PID COMMAND %CPU TIME MEM
10025 java 10.5 00:10.23 1024M
20036 chrome 5.2 00:05.12 512M
2.1.3 常用操作
-
按 CPU 使用率排序:
- 运行
top
后,按P
键。
- 运行
-
按内存使用率排序:
- 运行
top
后,按M
键。
- 运行
-
刷新间隔设置:
- 运行
top
后,按d
键,然后输入刷新间隔(秒)。
- 运行
-
退出
top
:- 按
Ctrl + C
或q
键。
- 按
2.1.4 Windows 替代工具
在 Windows 系统中,可以使用以下命令查看进程信息:
-
tasklist
:tasklist
输出示例:
Image Name PID Session Name Session# Mem Usage ========================= ======== ================ =========== ============ java.exe 10025 Console 1 102,400 K chrome.exe 20036 Console 1 512,000 K
-
任务管理器:
- 通过
Ctrl + Shift + Esc
打开任务管理器,查看进程和资源使用情况。
- 通过
2.2 vmstat:监控内存和 CPU
vmstat
(Virtual Memory Statistics)是 Linux 系统上的一款性能监控工具,用于统计系统的 CPU、内存、swap、I/O 等资源的使用情况。它能够帮助开发者快速了解系统的整体性能状况,识别资源瓶颈。
2.2.1 命令格式
vmstat [options] [delay [count]]
options
:可选参数,用于指定输出内容。delay
:采样间隔时间,单位为秒。count
:采样次数。
2.2.2 基本用法
-
实时监控:
vmstat 1 3
- 每秒采样一次,共采样 3 次。
-
持续监控:
vmstat 1
- 每秒采样一次,持续输出,按
Ctrl + C
退出。
- 每秒采样一次,持续输出,按
2.2.3 输出解析
vmstat
的输出分为两部分:系统资源概览和详细统计信息。
示例输出:
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 100000 20000 300000 0 0 10 20 100 200 5 2 93 0 0
0 0 0 98000 21000 310000 0 0 15 25 110 210 6 1 93 0 0
字段说明:
-
procs(进程):
r
:等待运行的进程数。b
:处于不可中断睡眠状态的进程数。
-
memory(内存):
swpd
:使用的虚拟内存大小(swap)。free
:空闲的物理内存大小。buff
:用作缓冲区的内存大小。cache
:用作缓存的内存大小。
-
swap(交换分区):
si
:每秒从磁盘读入 swap 的数据量(KB)。so
:每秒写入磁盘的 swap 数据量(KB)。
-
io(I/O):
bi
:每秒从块设备读入的数据量(KB)。bo
:每秒写入块设备的数据量(KB)。
-
system(系统):
in
:每秒的中断次数。cs
:每秒的上下文切换次数。
-
cpu(CPU):
us
:用户进程占用的 CPU 百分比。sy
:系统内核占用的 CPU 百分比。id
:CPU 空闲百分比。wa
:等待 I/O 操作的 CPU 百分比。st
:虚拟机占用的 CPU 百分比。
2.2.4 常用选项
选项 | 描述 |
---|---|
-a | 显示活跃和非活跃内存。 |
-d | 显示磁盘统计信息。 |
-s | 显示内存统计信息。 |
-p | 显示指定分区的 I/O 统计信息。 |
-t | 在输出中增加时间戳。 |
示例用法
-
显示活跃和非活跃内存:
vmstat -a 1 3
输出示例:
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free inact active si so bi bo in cs us sy id wa st 1 0 0 100000 200000 300000 0 0 10 20 100 200 5 2 93 0 0
-
显示磁盘统计信息:
vmstat -d 1 3
输出示例:
disk- ------------reads------------ ------------writes----------- -----IO------ total merged sectors ms total merged sectors ms cur sec sda 1000 200 100000 500 500 100 50000 300 0 0
-
显示内存统计信息:
vmstat -s
输出示例:
1000000 total memory 800000 used memory 200000 active memory 100000 inactive memory 50000 free memory
-
显示指定分区的 I/O 统计信息:
vmstat -p /dev/sda1 1 3
输出示例:
sda1 reads read sectors writes requested writes 1000 100000 500 50000
2.3 iostat:监控 IO 使用
iostat
(Input/Output Statistics)是 Linux 系统上的一款性能监控工具,用于统计 CPU 使用情况和磁盘的 I/O 信息。它能够帮助开发者分析系统的 I/O 性能,识别磁盘瓶颈。
2.3.1 命令格式
iostat [options] [interval [count]]
options
:可选参数,用于指定输出内容。interval
:采样间隔时间,单位为秒。count
:采样次数。
2.3.2 输出解析
iostat
的输出分为两部分:CPU 使用情况和磁盘 I/O 统计。
示例输出:
Linux 5.4.0-42-generic (hostname) 09/01/2023 _x86_64_ (4 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
5.23 0.00 1.23 0.12 0.00 93.42
Device tps kB_read/s kB_wrtn/s kB_read kB_wrtn
sda 1.23 10.00 20.00 100000 200000
字段说明:
-
CPU 使用情况:
%user
:用户进程占用的 CPU 百分比。%nice
:低优先级用户进程占用的 CPU 百分比。%system
:系统内核占用的 CPU 百分比。%iowait
:等待 I/O 操作的 CPU 百分比。%steal
:虚拟机被其他虚拟机占用的 CPU 百分比。%idle
:CPU 空闲百分比。
-
磁盘 I/O 统计:
tps
:每秒传输次数(Transfers Per Second)。kB_read/s
:每秒读取的数据量(KB)。kB_wrtn/s
:每秒写入的数据量(KB)。kB_read
:读取的总数据量(KB)。kB_wrtn
:写入的总数据量(KB)。
2.3.3 常用选项
选项 | 描述 |
---|---|
-c | 只显示 CPU 使用情况。 |
-d | 只显示磁盘 I/O 统计信息。 |
-x | 显示扩展的磁盘 I/O 统计信息。 |
-p | 显示指定磁盘分区的 I/O 统计信息。 |
-t | 在输出中增加时间戳。 |
示例用法
-
查看 CPU 和所有磁盘设备的基本 I/O 统计信息:
iostat
输出示例:
avg-cpu: %user %nice %system %iowait %steal %idle 5.23 0.00 1.23 0.12 0.00 93.42 Device tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 1.23 10.00 20.00 100000 200000
-
查看磁盘 I/O 统计信息,每 2 秒更新一次:
iostat -d 2
输出示例:
Device tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 1.23 10.00 20.00 100000 200000 sda 1.50 15.00 25.00 150000 250000
-
查看扩展的磁盘 I/O 统计信息:
iostat -x
输出示例:
Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %rrqm %wrqm r_await w_await svctm %util sda 0.50 0.73 10.00 20.00 0.00 0.00 0.00 0.00 1.23 2.34 0.56 0.12
扩展字段说明:
r/s
:每秒读取次数。w/s
:每秒写入次数。rkB/s
:每秒读取的数据量(KB)。wkB/s
:每秒写入的数据量(KB)。rrqm/s
:每秒合并的读取请求数。wrqm/s
:每秒合并的写入请求数。%rrqm
:读取请求合并的百分比。%wrqm
:写入请求合并的百分比。r_await
:读取请求的平均等待时间(毫秒)。w_await
:写入请求的平均等待时间(毫秒)。svctm
:I/O 请求的平均服务时间(毫秒)。%util
:磁盘的繁忙程度(百分比)。
-
只查看 CPU 使用情况:
iostat -c
输出示例:
avg-cpu: %user %nice %system %iowait %steal %idle 5.23 0.00 1.23 0.12 0.00 93.42
-
查看指定磁盘分区的 I/O 统计信息:
iostat -p sda1
输出示例:
Device tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda1 1.23 10.00 20.00 100000 200000
2.4 netstat:监控网络使用
netstat
(Network Statistics)是一个常用的命令行工具,用于监控和显示网络相关信息,包括网络连接、路由表、接口统计等。它能够帮助开发者分析网络状态,诊断网络问题。
2.4.1 命令格式
netstat [options]
options
:可选参数,用于指定输出内容。
2.4.2 常用选项
选项 | 描述 |
---|---|
-a | 显示所有连接和侦听端口。 |
-t | 显示 TCP 连接。 |
-u | 显示 UDP 连接。 |
-n | 以数字形式显示地址和端口号(不解析主机名和服务名)。 |
-r | 显示路由表。 |
-l | 显示侦听中的套接字。 |
-p | 显示与套接字关联的进程 ID 和程序名称。 |
-s | 显示网络协议的统计信息。 |
-c | 持续输出网络信息,按 Ctrl + C 退出。 |
2.4.3 输出解析
netstat
的输出通常包括以下几个方面的信息:
-
网络连接:
- 显示活动的或监听的套接字连接,包括协议、本地地址和端口、远程地址和端口、连接状态等。
-
路由表:
- 显示网络路由表,包括目的地址、网关、子网掩码、使用的接口等。
示例用法
-
显示所有连接和侦听端口:
netstat -a
输出示例:
Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN tcp 0 0 192.168.1.100:22 192.168.1.200:54321 ESTABLISHED udp 0 0 0.0.0.0:68 0.0.0.0:*
-
显示 TCP 连接:
netstat -t
输出示例:
Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 192.168.1.100:22 192.168.1.200:54321 ESTABLISHED
-
显示 UDP 连接:
netstat -u
输出示例:
Proto Recv-Q Send-Q Local Address Foreign Address State udp 0 0 0.0.0.0:68 0.0.0.0:*
-
以数字形式显示地址和端口号:
netstat -n
输出示例:
Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 192.168.1.100:22 192.168.1.200:54321 ESTABLISHED
-
显示路由表:
netstat -r
输出示例:
Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface default 192.168.1.1 0.0.0.0 UG 0 0 0 eth0 192.168.1.0 * 255.255.255.0 U 0 0 0 eth0
-
显示侦听中的套接字:
netstat -l
输出示例:
Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
-
显示与套接字关联的进程 ID 和程序名称:
netstat -p
输出示例:
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 192.168.1.100:22 192.168.1.200:54321 ESTABLISHED 1234/sshd
-
显示网络协议的统计信息:
netstat -s
输出示例:
Ip: 1000 total packets received 0 forwarded 0 incoming packets discarded 1000 incoming packets delivered 1000 requests sent out
-
持续输出网络信息:
netstat -c
- 持续输出网络信息,按
Ctrl + C
退出。
- 持续输出网络信息,按
3 总结
JDK 提供的性能监控工具和操作系统命令行工具是开发者排查问题、优化性能的利器。掌握这些工具的使用方法,能够帮助开发者在面对内存泄漏、线程死锁等问题时,快速定位并解决问题。希望本文的介绍能够为开发者提供有价值的参考。
4 思维导图
5 参考链接
JVM 性能监控工具之命令行篇