JVM 性能监控工具之命令行篇

在 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 工具(如 jstackjmap 等)进行诊断提供便利。

1.1.1 命令格式

bash 复制代码
jps [options] [hostid]
  • options:可选参数,用于控制输出内容。
  • hostid:可选参数,用于指定远程主机的标识符(通常用于远程监控)。

命令示例

运行 jps 命令后,输出结果可能如下:

bash 复制代码
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 的进程:

    bash 复制代码
    kill -9 54321

    注意kill -9 会强制终止进程,可能导致数据丢失或应用异常退出,生产环境中需谨慎使用。

1.1.3 常用选项

选项 描述
-q 只输出进程 ID,忽略主类信息。
-l 输出主类的全名,如果进程是通过 JAR 包启动的,则输出 JAR 文件的完整路径。
-m 输出虚拟机进程启动时传递给主类 main() 方法的参数。
-v 输出虚拟机进程启动时的 JVM 参数。

示例用法

  1. 查看所有 Java 进程及其主类全名:

    bash 复制代码
    jps -l

    输出示例:

    bash 复制代码
    12345 com.example.MainClass
    67890 /path/to/AnotherApp.jar
  2. 查看 Java 进程的 JVM 启动参数:

    bash 复制代码
    jps -v

    输出示例:

    bash 复制代码
    12345 MainClass -Xms512m -Xmx1024m
  3. 只查看 Java 进程的 PID:

    bash 复制代码
    jps -q

    输出示例:

    bash 复制代码
    12345
    67890

1.2 jstat:查看 JVM 运行时信息

jstat(Java Virtual Machine Statistics Monitoring Tool)是 JDK 提供的一个命令行工具,用于监控 JVM 的各种运行时状态信息。它能够提供关于垃圾回收、类加载、JIT 编译等方面的详细数据,帮助开发者分析和优化 Java 应用的性能。

1.2.1 命令格式

bash 复制代码
jstat [option vmid [interval[s|ms] [count]]]
  • option:指定监控的类别,例如类加载、垃圾回收等。
  • vmid:目标 Java 进程的进程 ID(PID)。
  • interval:采样间隔时间,单位为秒(s)或毫秒(ms)。
  • count:采样次数。

1.2.2 主要选项

jstat 的选项主要分为三类:类加载、垃圾回收、运行期编译状况。以下是常用选项及其功能:

1. -class:监视类加载信息

用于监控类的加载、卸载数量、总空间以及类加载所耗费的时间。

命令示例:

bash 复制代码
jstat -class -t 75952 1000 2

输出示例:

bash 复制代码
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 区、老年代等)的容量、已用空间以及垃圾回收的时间和次数。

命令示例:

bash 复制代码
jstat -gc 75952 1000 2

输出示例:

bash 复制代码
 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

字段说明:

  • S0CS1C:Survivor 0 区和 Survivor 1 区的当前容量(Current)。
  • S0US1U:Survivor 0 区和 Survivor 1 区的已使用空间(Used)。
  • ECEU:Eden 区的容量和已使用空间。
  • OCOU:老年代的容量和已使用空间。
  • MCMU:元空间(Metaspace)的容量和已使用空间。
  • YGCYGCT:年轻代垃圾回收的次数和总时间。
  • FGCFGCT:老年代垃圾回收(Full GC)的次数和总时间。
  • GCT:垃圾回收的总时间。

3. -compiler:监视 JIT 编译信息

用于监控 JIT(Just-In-Time)编译器编译过的方法、耗时等信息。

命令示例:

bash 复制代码
jstat -compiler 75952 1000 2

输出示例:

bash 复制代码
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 的各项配置参数。它的主要功能包括:

  1. 查看 JVM 参数:输出当前 Java 进程的 JVM 启动参数。
  2. 动态修改参数:在不重启应用的情况下,调整某些 JVM 参数(仅限于支持动态修改的参数)。

1.3.1 命令格式

bash 复制代码
jinfo [option] pid
  • option:可选参数,用于指定操作类型。
  • pid:目标 Java 进程的进程 ID。

1.3.2 常用选项

选项 描述
-flags 输出 JVM 的启动参数。
-sysprops 输出 Java 系统属性(等同于 System.getProperties())。
-flag <name> 查看某个特定 JVM 参数的值。
`-flag [+ -]<name>`

1.3.3 示例用法

  1. 查看 JVM 启动参数:

    bash 复制代码
    jinfo -flags 88952

    输出示例:

    bash 复制代码
    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
  2. 查看 Java 系统属性:

    bash 复制代码
    jinfo -sysprops 88952

    输出示例:

    bash 复制代码
    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
    ...
  3. 查看特定 JVM 参数的值:

    bash 复制代码
    jinfo -flag MaxHeapSize 88952

    输出示例:

    bash 复制代码
    -XX:MaxHeapSize=4294967296
  4. 动态修改 JVM 参数:

    bash 复制代码
    jinfo -flag +PrintGCDetails 88952

    注意:并非所有 JVM 参数都支持动态修改,具体取决于 JVM 实现和参数类型。

1.3.4 常见问题及解决方法

问题:jinfo 命令无法执行成功,提示无法附加到进程。

可能原因:

  1. JDK 版本不一致:jinfo 工具的版本与目标 Java 进程使用的 JDK 版本不一致。
  2. 权限不足:当前用户没有权限访问目标进程。
  3. JDK 版本过旧:某些旧版本 JDK 可能存在兼容性问题。

解决方法:

  1. 确保 JDK 版本一致:

    • 使用与目标 Java 进程相同的 JDK 版本的 jinfo 工具。
    • 例如,如果目标进程使用 JDK 11,则确保 jinfo 也来自 JDK 11。
  2. 使用管理员权限运行:

    • 在 Linux/macOS 上,尝试使用 sudo 提升权限:

      bash 复制代码
      sudo jinfo -flags <pid>
  3. 升级 JDK 版本:

    • 如果使用的是较旧的 JDK 版本,尝试升级到较新的稳定版本(如 JDK 11 或 JDK 17)。

示例:

bash 复制代码
# 使用 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 命令格式

bash 复制代码
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 示例用法

  1. 生成堆转储快照:

    bash 复制代码
    jmap -dump:format=b,file=heap.hprof 10025
    • format=b:指定文件格式为二进制。
    • file=heap.hprof:指定输出文件名为 heap.hprof
    • 10025:目标 Java 进程的 PID。

    说明:

    • 生成的堆转储文件(heap.hprof)可以使用工具(如 Eclipse MAT、VisualVM)进行分析。
  2. 查看堆中对象统计信息:

    bash 复制代码
    jmap -histo 10025

    输出示例:

    bash 复制代码
    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:类名。
  3. 显示 Java 堆详细信息:

    bash 复制代码
    jmap -heap 10025

    输出示例:

    bash 复制代码
    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
       ...
  4. 强制生成堆转储快照:

    bash 复制代码
    jmap -F -dump:format=b,file=heap.hprof 10025
    • 当目标进程无响应时,使用 -F 选项强制生成堆转储。

1.4.4 堆转储文件分析工具

生成的堆转储文件(如 heap.hprof)可以使用以下工具进行分析:

  1. Eclipse MAT(Memory Analyzer Tool)

    • 功能强大,支持内存泄漏分析、对象依赖关系查看等。
    • 下载地址:Eclipse MAT
  2. VisualVM

    • JDK 自带的图形化工具,支持堆转储分析和性能监控。
    • 启动命令:jvisualvm
  3. JProfiler

    • 商业工具,提供全面的性能分析和堆转储分析功能。
    • 官网:JProfiler

1.5 jstack:跟踪 Java 堆栈

jstack 是 JDK 提供的一个命令行工具,用于打印 JVM 中某个进程的线程堆栈信息(通常称为 threaddump 或 javacore 文件)。它常用于诊断应用程序中的线程问题,如线程死锁、死循环或长时间等待。

1.5.1 命令格式

bash 复制代码
jstack [option] vmid
  • option:可选参数,用于控制输出内容。
  • vmid:目标 Java 进程的进程 ID(PID)。

1.5.2 常用选项

选项 描述
-F 当正常输出的请求不被响应时,强制输出线程堆栈。
-l 除了堆栈信息外,显示关于锁的附加信息(如持有的锁、等待的锁等)。
-m 如果调用的是本地方法(Native Method),显示 C/C++ 的堆栈信息。

1.5.3 示例用法

  1. 打印线程堆栈信息:

    bash 复制代码
    jstack 10025

    输出示例:

    bash 复制代码
    "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)
  2. 打印线程堆栈信息及锁信息:

    bash 复制代码
    jstack -l 10025

    输出示例:

    bash 复制代码
    "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)
  3. 强制打印线程堆栈信息:

    bash 复制代码
    jstack -F 10025
    • 当目标进程无响应时,使用 -F 选项强制输出线程堆栈。

1.5.4 诊断死锁问题

以下是一个简单的死锁示例程序:

java 复制代码
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 诊断死锁:

bash 复制代码
jstack -l <pid>

输出示例:

bash 复制代码
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 提供的一个多功能命令行工具,集成了 jstackjmapjstatjinfo 等工具的功能。它能够收集堆转储、生成 JVM 和 Java 应用程序的性能数据,以及动态更改某些 Java 运行时参数。jcmd 的强大之处在于它可以通过单一命令完成多种任务,简化了 JVM 监控和诊断的操作。

1.6.1 命令格式

bash 复制代码
jcmd <pid | main class> <command ... | PerfCounter.print | -f file>
  • pid:目标 Java 进程的进程 ID。
  • main class:目标 Java 应用的主类名。
  • command:要执行的操作或命令。
  • PerfCounter.print:打印性能计数器信息。
  • -f file:从文件中读取命令并执行。

1.6.2 常用功能

  1. 列出所有 Java 应用:

    bash 复制代码
    jcmd -l

    输出示例:

    java 复制代码
    10025 com.example.MainClass
    20036 org.apache.catalina.startup.Bootstrap
  2. 查看支持的命令:

    bash 复制代码
    jcmd 10025 help

    输出示例:

    java 复制代码
    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
  3. 查看 JVM 参数:

    bash 复制代码
    jcmd 10025 VM.flags

    输出示例:

    bash 复制代码
    -XX:CICompilerCount=4 -XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4294967296 ...
  4. 打印线程信息:

    bash 复制代码
    jcmd 10025 Thread.print

    输出示例:

    bash 复制代码
    "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)
  5. 生成堆转储文件:

    bash 复制代码
    jcmd 10025 GC.heap_dump filename=heap.hprof

    说明:

    • 生成的堆转储文件(heap.hprof)可以使用工具(如 Eclipse MAT、VisualVM)进行分析。
  6. 打印性能计数器信息:

    bash 复制代码
    jcmd 10025 PerfCounter.print

    输出示例:

    bash 复制代码
    java.ci.totalTime=123456
    java.cls.loadedClasses=5000
    java.cls.unloadedClasses=100
    ...
  7. 查看系统属性:

    bash 复制代码
    jcmd 10025 VM.system_properties

    输出示例:

    bash 复制代码
    java.runtime.name=Java(TM) SE Runtime Environment
    java.vm.version=11.0.12+7-LTS
    user.country=CN
    ...
  8. 查看 JVM 启动时间:

    bash 复制代码
    jcmd 10025 VM.uptime

    输出示例:

    bash 复制代码
    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 命令格式

bash 复制代码
top
  • 默认情况下,top 会实时更新显示信息,按 Ctrl + C 退出。

2.1.2 输出解析

top 的输出分为两部分:统计信息进程信息

1. 统计信息

统计信息部分提供了系统的整体资源使用情况,主要包括以下内容:

  1. 进程和线程信息:

    bash 复制代码
    Processes: 500 total, 10 running, 490 sleeping, 2000 threads
    • Processes:总进程数。
    • running:正在运行的进程数。
    • sleeping:睡眠的进程数。
    • threads:总线程数。
  2. 负载均衡和 CPU 使用率:

    bash 复制代码
    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 空闲百分比。
  3. 共享库内存使用:

    bash 复制代码
    SharedLibs: 100M resident, 50M data, 10M linkedit.
    • 显示操作系统加载的共享库(如动态链接库)的内存使用情况。
  4. 内存区域使用:

    bash 复制代码
    MemRegions: 5000 total, 100M resident, 50M private, 200M shared.
    • 显示系统内存区域的使用情况,包括代码、数据、堆、栈等。
  5. 物理内存使用:

    bash 复制代码
    PhysMem: 30G used (3018M wired), 1547M unused.
    • used:已使用的物理内存。
    • wired:被锁定在内存中的部分(不可被交换到磁盘)。
    • unused:未使用的物理内存。
  6. 虚拟内存信息:

    bash 复制代码
    VM: 50G vsize, 20G framework vsize, 10G swapins, 5G swapouts.
    • vsize:虚拟内存总量。
    • swapins:从磁盘交换到内存的数据量。
    • swapouts:从内存交换到磁盘的数据量。
  7. 网络和硬盘信息:

    bash 复制代码
    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。

示例:

bash 复制代码
PID    COMMAND          %CPU  TIME     MEM
10025  java             10.5  00:10.23 1024M
20036  chrome           5.2   00:05.12 512M

2.1.3 常用操作

  1. 按 CPU 使用率排序:

    • 运行 top 后,按 P 键。
  2. 按内存使用率排序:

    • 运行 top 后,按 M 键。
  3. 刷新间隔设置:

    • 运行 top 后,按 d 键,然后输入刷新间隔(秒)。
  4. 退出 top

    • Ctrl + Cq 键。

2.1.4 Windows 替代工具

在 Windows 系统中,可以使用以下命令查看进程信息:

  1. tasklist

    bash 复制代码
    tasklist

    输出示例:

    bash 复制代码
    Image Name                     PID Session Name        Session#    Mem Usage
    ========================= ======== ================ =========== ============
    java.exe                      10025 Console                    1     102,400 K
    chrome.exe                    20036 Console                    1     512,000 K
  2. 任务管理器:

    • 通过 Ctrl + Shift + Esc 打开任务管理器,查看进程和资源使用情况。

2.2 vmstat:监控内存和 CPU

vmstat(Virtual Memory Statistics)是 Linux 系统上的一款性能监控工具,用于统计系统的 CPU、内存、swap、I/O 等资源的使用情况。它能够帮助开发者快速了解系统的整体性能状况,识别资源瓶颈。

2.2.1 命令格式

bash 复制代码
vmstat [options] [delay [count]]
  • options:可选参数,用于指定输出内容。
  • delay:采样间隔时间,单位为秒。
  • count:采样次数。

2.2.2 基本用法

  1. 实时监控:

    bash 复制代码
    vmstat 1 3
    • 每秒采样一次,共采样 3 次。
  2. 持续监控:

    bash 复制代码
    vmstat 1
    • 每秒采样一次,持续输出,按 Ctrl + C 退出。

2.2.3 输出解析

vmstat 的输出分为两部分:系统资源概览详细统计信息

示例输出:

bash 复制代码
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

字段说明:

  1. procs(进程):

    • r:等待运行的进程数。
    • b:处于不可中断睡眠状态的进程数。
  2. memory(内存):

    • swpd:使用的虚拟内存大小(swap)。
    • free:空闲的物理内存大小。
    • buff:用作缓冲区的内存大小。
    • cache:用作缓存的内存大小。
  3. swap(交换分区):

    • si:每秒从磁盘读入 swap 的数据量(KB)。
    • so:每秒写入磁盘的 swap 数据量(KB)。
  4. io(I/O):

    • bi:每秒从块设备读入的数据量(KB)。
    • bo:每秒写入块设备的数据量(KB)。
  5. system(系统):

    • in:每秒的中断次数。
    • cs:每秒的上下文切换次数。
  6. cpu(CPU):

    • us:用户进程占用的 CPU 百分比。
    • sy:系统内核占用的 CPU 百分比。
    • id:CPU 空闲百分比。
    • wa:等待 I/O 操作的 CPU 百分比。
    • st:虚拟机占用的 CPU 百分比。

2.2.4 常用选项

选项 描述
-a 显示活跃和非活跃内存。
-d 显示磁盘统计信息。
-s 显示内存统计信息。
-p 显示指定分区的 I/O 统计信息。
-t 在输出中增加时间戳。

示例用法

  1. 显示活跃和非活跃内存:

    bash 复制代码
    vmstat -a 1 3

    输出示例:

    bash 复制代码
    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
  2. 显示磁盘统计信息:

    bash 复制代码
    vmstat -d 1 3

    输出示例:

    bash 复制代码
    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
  3. 显示内存统计信息:

    bash 复制代码
    vmstat -s

    输出示例:

    bash 复制代码
        1000000  total memory
        800000   used memory
        200000   active memory
        100000   inactive memory
        50000    free memory
  4. 显示指定分区的 I/O 统计信息:

    bash 复制代码
    vmstat -p /dev/sda1 1 3

    输出示例:

    bash 复制代码
    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 命令格式

bash 复制代码
iostat [options] [interval [count]]
  • options:可选参数,用于指定输出内容。
  • interval:采样间隔时间,单位为秒。
  • count:采样次数。

2.3.2 输出解析

iostat 的输出分为两部分:CPU 使用情况磁盘 I/O 统计

示例输出:

bash 复制代码
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

字段说明:

  1. CPU 使用情况:

    • %user:用户进程占用的 CPU 百分比。
    • %nice:低优先级用户进程占用的 CPU 百分比。
    • %system:系统内核占用的 CPU 百分比。
    • %iowait:等待 I/O 操作的 CPU 百分比。
    • %steal:虚拟机被其他虚拟机占用的 CPU 百分比。
    • %idle:CPU 空闲百分比。
  2. 磁盘 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 在输出中增加时间戳。

示例用法

  1. 查看 CPU 和所有磁盘设备的基本 I/O 统计信息:

    bash 复制代码
    iostat

    输出示例:

    bash 复制代码
    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
  2. 查看磁盘 I/O 统计信息,每 2 秒更新一次:

    bash 复制代码
    iostat -d 2

    输出示例:

    bash 复制代码
    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
  3. 查看扩展的磁盘 I/O 统计信息:

    bash 复制代码
    iostat -x

    输出示例:

    bash 复制代码
    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:磁盘的繁忙程度(百分比)。
  4. 只查看 CPU 使用情况:

    bash 复制代码
    iostat -c

    输出示例:

    bash 复制代码
    avg-cpu:  %user   %nice %system %iowait  %steal   %idle
               5.23    0.00    1.23    0.12    0.00   93.42
  5. 查看指定磁盘分区的 I/O 统计信息:

    bash 复制代码
    iostat -p sda1

    输出示例:

    bash 复制代码
    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 命令格式

bash 复制代码
netstat [options]
  • options:可选参数,用于指定输出内容。

2.4.2 常用选项

选项 描述
-a 显示所有连接和侦听端口。
-t 显示 TCP 连接。
-u 显示 UDP 连接。
-n 以数字形式显示地址和端口号(不解析主机名和服务名)。
-r 显示路由表。
-l 显示侦听中的套接字。
-p 显示与套接字关联的进程 ID 和程序名称。
-s 显示网络协议的统计信息。
-c 持续输出网络信息,按 Ctrl + C 退出。

2.4.3 输出解析

netstat 的输出通常包括以下几个方面的信息:

  1. 网络连接:

    • 显示活动的或监听的套接字连接,包括协议、本地地址和端口、远程地址和端口、连接状态等。
  2. 路由表:

    • 显示网络路由表,包括目的地址、网关、子网掩码、使用的接口等。

示例用法

  1. 显示所有连接和侦听端口:

    bash 复制代码
    netstat -a

    输出示例:

    bash 复制代码
    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:*
  2. 显示 TCP 连接:

    bash 复制代码
    netstat -t

    输出示例:

    bash 复制代码
    Proto Recv-Q Send-Q Local Address           Foreign Address         State
    tcp        0      0 192.168.1.100:22       192.168.1.200:54321     ESTABLISHED
  3. 显示 UDP 连接:

    bash 复制代码
    netstat -u

    输出示例:

    bash 复制代码
    Proto Recv-Q Send-Q Local Address           Foreign Address         State
    udp        0      0 0.0.0.0:68             0.0.0.0:*
  4. 以数字形式显示地址和端口号:

    bash 复制代码
    netstat -n

    输出示例:

    bash 复制代码
    Proto Recv-Q Send-Q Local Address           Foreign Address         State
    tcp        0      0 192.168.1.100:22       192.168.1.200:54321     ESTABLISHED
  5. 显示路由表:

    bash 复制代码
    netstat -r

    输出示例:

    bash 复制代码
    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
  6. 显示侦听中的套接字:

    bash 复制代码
    netstat -l

    输出示例:

    bash 复制代码
    Proto Recv-Q Send-Q Local Address           Foreign Address         State
    tcp        0      0 0.0.0.0:22             0.0.0.0:*               LISTEN
  7. 显示与套接字关联的进程 ID 和程序名称:

    bash 复制代码
    netstat -p

    输出示例:

    bash 复制代码
    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
  8. 显示网络协议的统计信息:

    bash 复制代码
    netstat -s

    输出示例:

    bash 复制代码
    Ip:
       1000 total packets received
       0 forwarded
       0 incoming packets discarded
       1000 incoming packets delivered
       1000 requests sent out
  9. 持续输出网络信息:

    bash 复制代码
    netstat -c
    • 持续输出网络信息,按 Ctrl + C 退出。

3 总结

JDK 提供的性能监控工具和操作系统命令行工具是开发者排查问题、优化性能的利器。掌握这些工具的使用方法,能够帮助开发者在面对内存泄漏、线程死锁等问题时,快速定位并解决问题。希望本文的介绍能够为开发者提供有价值的参考。

4 思维导图

5 参考链接

JVM 性能监控工具之命令行篇

相关推荐
深鱼~37 分钟前
【多线程初阶篇 ²】创建线程的方式
java·开发语言·jvm·深度学习·神经网络·opencv
LiuYuHani4 小时前
jvm基础
jvm
Chancezhou4 小时前
【JVM】总结篇-类的加载篇之 类的加载器 和ClassLoader分析
jvm
东阳马生架构16 小时前
JVM实战—12.OOM的定位和解决
jvm
啊烨疯狂学java19 小时前
0105java字节面经
java·jvm·算法
神的孩子都在歌唱21 小时前
你已经分清JAVA中JVM、JDK与JRE的作用和关系了吗?
java·开发语言·jvm
吴冰_hogan1 天前
ThreadLocal详解:深入探讨导致JVM内存泄露的原因及预防措施
java·开发语言·jvm