菜鸟科技网

jvm监控命令

下面我将从 命令行工具可视化工具Java 内置 API 三个层面,为你详细介绍常用的 JVM 监控命令和方法,并提供实际案例。

jvm监控命令-图1
(图片来源网络,侵删)

命令行工具

这些是 JVM 自带的、最常用、最直接的监控工具,通常在 JDK 的 bin 目录下。

jps - Java Virtual Machine Process Status Tool

作用:列出当前正在运行的 Java 进程的 ID 和主类名。

常用选项

  • jps:只显示进程 ID 和主类名。
  • jps -l:显示完整的主类包名或 JAR 文件名。
  • jps -v:显示传递给 JVM 的参数。
  • jps -m:显示传递给 main 方法的参数。

示例

jvm监控命令-图2
(图片来源网络,侵删)
# 列出所有 Java 进程
$ jps -l
12345 /path/to/your/application.jar
67890 org.apache.catalina.startup.Bootstrap
# 查看某个 JVM 的启动参数
$ jps -v 12345
...
-XX:+UseG1GC -Xms512m -Xmx512m ...

jstat - JVM Statistics Monitoring Tool

作用:监控 JVM 的运行时行为,包括堆内存、垃圾回收(GC)情况等,这是分析 GC 问题的核心工具。

常用选项

  • jstat -gc <pid>:查看 GC 的详细信息(堆内、堆外)。
    • S0C, S1C:Survivor 0/1 区的容量。
    • S0U, S1U:Survivor 0/1 区的使用量。
    • EC, EU:Eden 区的容量和使用量。
    • OC, OU:Old 区的容量和使用量。
    • MC, MU:元空间的容量和使用量。
    • CCSC, CCSU:压缩类空间容量和使用量。
    • YGC, YGT:Young GC 次数和耗时。
    • FGC, FGCT:Full GC 次数和耗时。
    • GCT:总 GC 耗时。
    • GCC:GC 时间占总时间的百分比。
  • jstat -gcutil <pid>:以百分比形式展示内存使用情况,更直观。
  • jstat -gccapacity <pid>:查看各内存区域的最大、最小和当前容量。
  • jstat -gcnew <pid>:查看新生代 GC 情况。
  • jstat -gcold <pid>:查看老年代 GC 情况。
  • jstat -t <pid>:在输出中带有一个时间戳,方便观察随时间变化。

示例

# 每 1 秒监控一次 PID 为 12345 的进程的 GC 情况
$ jstat -gcutil 12345 1000
 S0    S1    E     O     M    CCS    YGC     YGT    FGC    FGCT     GCT    GCC    LGCT    SCT    TT    FTMT    TMA
  0.00  0.00  30.45 65.12 95.43  90.12      5    0.123     2    0.456   0.579  0.456    0.01    0.00       2.0       1.0
  0.00  0.00  45.12 65.12 95.43  90.12      5    0.123     2    0.456   0.579  0.456    0.01    0.00       2.0       1.0
# 从输出可以看出,Eden 区使用率在持续上升,很快就要触发 Young GC 了。

jmap - Memory Map for Java

作用:生成 Java 堆的转储快照(Heap Dump),或者查看堆内存的详细信息。

jvm监控命令-图3
(图片来源网络,侵删)

常用选项

  • jmap -histo <pid>:查看堆中对象的实例数量和大小分布,按占用内存大小降序排列,可以快速发现占用内存最多的对象。
    • num:对象数量。
    • #instances:同上。
    • #bytes:占用总字节数。
    • class name:类名。
  • jmap -dump:format=b,file=<filename.hprof> <pid>:生成一个二进制的堆转储文件(.hprof),这个文件可以用 MATVisualVM 等工具分析,是定位内存泄漏的利器。
  • jmap -heap <pid>:查看 JVM 的堆内存配置信息,包括使用的垃圾回收器、各区域大小等。

示例

# 查看堆中对象的分布
$ jmap -histo 12345
 num     #instances         #bytes  class name
----------------------------------------------
   1:         12345       12345000  [C  (char数组)
   2:         10000       10000000  java.lang.String
   3:            50         500000  com.example.YourLeakyObject
# 生成堆转储文件
$ jmap -dump:format=b,file=heapdump_12345.hprof 12345

jstack - Java Stack Trace

作用:生成指定 Java 进程的线程快照(Thread Dump),可以用来分析线程状态、死锁、CPU 100% 等问题。

常用选项

  • jstack <pid>:生成线程快照。
  • jstack -l <pid>:生成更详细的线程快照,包含锁的信息。
  • jstack -F <pid>:当进程没有响应时,强制生成线程快照。

如何分析线程快照

  1. 找到 RUNNABLE 状态的线程,特别是 CPU 占用高的线程(nid 对应系统的线程 ID,可以用 top -H -p <pid> 找到具体是哪个线程)。
  2. 查找 BLOCKED 状态的线程,看是否存在线程等待锁。
  3. 搜索 Found one Java-level deadlock!,直接定位死锁问题。

示例

# 生成线程快照
$ jstack 12345 > threaddump_12345.log
# 在 Linux 上找到 CPU 占用高的线程
$ top -H -p 12345
# 假设发现 nid 为 0x1234 的线程 CPU 占用 99%
# 然后在 threaddump 文件中搜索 nid 0x1234
$ grep 0x1234 threaddump_12345.log
"Thread-0" #1234 prio=5 os_prio=0 cpu=98.45% elapsed=10.23s tid=0x00007f8c00000400 nid=0x1234 runnable  [0x00007f8c...]
   java.lang.Thread.State: RUNNABLE
        at com.example.YourCPUHungryMethod(Native Method)
        at com.example.YourCPUHungryMethod(YourCPUHungryMethod.java:50)
        ...

jcmd - The Command Line Interface for the JVM

作用:一个多功能工具,可以替代 jps, jinfo, jmap, jstack 等多个命令,它可以直接向 JVM 发送诊断命令,功能更强大。

常用选项

  • jcmd:列出所有 Java 进程及其可用的命令。
  • jcmd <pid> help:查看指定进程支持的所有命令。
  • jcmd <pid> GC.heap_info:查看堆内存信息(类似 jmap -heap)。
  • jcmd <pid> Thread.print:生成线程快照(类似 jstack)。
  • jcmd <pid> GC.class_histogram:查看对象实例分布(类似 jmap -histo)。
  • jcmd <pid> GC.heap_dump <filename.hprof>:生成堆转储(类似 jmap -dump)。
  • jcmd <pid> VM.native_memory summary:查看本地内存使用情况,对排查 Direct Memory 或 JNI 问题非常有用。

示例

# 列出所有进程和可用命令
$ jcmd
12345 com.example.Main
67890 org.apache.catalina.startup.Bootstrap
# 查看进程 12345 的所有可用命令
$ jcmd 12345 help
# 生成堆转储
$ jcmd 12345 GC.heap_dump heapdump_jcmd.hprof
# 查看本地内存使用
$ jcmd 12345 VM.native_memory summary

可视化工具

对于不习惯命令行的开发者,可视化工具提供了更直观的界面。

VisualVM

VisualVM 是 JDK 自带的图形化工具,功能非常全面,是监控本地和远程 JVM 的瑞士军刀。

如何启动

# 在 JDK bin 目录下
$ jvisualvm

主要功能

  • 监控:实时查看 CPU、堆内存、元空间、线程、类加载等信息。
  • Sampler:可以对 CPU 和内存进行抽样分析,找出热点代码和内存分配热点。
  • Visual GC:实时展示 GC 的活动情况,非常直观。
  • OQL (Object Query Language):类似 SQL 的查询语言,可以在堆转储文件中查询对象。
  • MBeans:查看和管理 JMX MBeans。

JConsole

JConsole 是另一个 JDK 自带的轻量级监控工具,基于 JMX,功能比 VisualVM 简单,但足以进行基本的监控。

如何启动

$ jconsole

主要功能

  • 显示内存使用情况。
  • 显示线程状态和死锁检测。
  • 显示类的加载情况。
  • 查看 VM 概要信息。

Eclipse MAT (Memory Analyzer Tool)

专门用于分析堆转储文件(.hprof)的强大工具。

主要功能

  • Leak Suspects Report:自动生成内存泄漏嫌疑报告,直接告诉你哪个对象是泄漏的根源。
  • Dominator Tree:支配者树,可以快速找到一组对象中最大的对象,以及被哪些对象强引用。
  • Histogram:直方图,查看对象实例数量和大小。
  • Path to GC Roots:查看一个对象到 GC Roots 的引用链,这是确定对象为何无法被回收的关键。

Java 内置 API (编程式监控)

在代码中集成监控,可以实现更灵活、自动化的监控。

java.lang.management

提供对 JVM 和操作系统管理信息的访问,是 JMX 的 Java 标准 API。

示例

import java.lang.management.*;
public class JvmInfo {
    public static void main(String[] args) {
        // 获取运行时信息
        RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
        System.out.println("JVM Name: " + runtimeBean.getVmName());
        System.out.println("JVM Version: " + runtimeBean.getVmVersion());
        System.out.println("Uptime (ms): " + runtimeBean.getUptime());
        // 获取内存信息
        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
        System.out.println("\nHeap Memory Usage:");
        System.out.println("  Used: " + heapUsage.getUsed() / 1024 / 1024 + " MB");
        System.out.println("  Max: " + heapUsage.getMax() / 1024 / 1024 + " MB");
        System.out.println("  Committed: " + heapUsage.getCommitted() / 1024 / 1024 + " MB");
        // 获取线程信息
        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        System.out.println("\nThread Count: " + threadBean.getThreadCount());
        System.out.println("Daemon Thread Count: " + threadBean.getDaemonThreadCount());
    }
}

JMX (Java Management Extensions)

JMX 是一个更强大的框架,允许你通过外部管理工具(如 VisualVM, JConsole, 或自定义的客户端)来监控和管理正在运行的 Java 应用。

如何暴露 MBean

  1. MBean 接口:定义一个接口,名称以 MBean
  2. MBean 实现:实现该接口。
  3. 注册 MBean:使用 MBeanServer 将你的 MBean 实现注册到 JVM 中。

示例

// 1. MBean 接口
public interface HelloMBean {
    String getName();
    void setName(String name);
    int getCacheSize();
    void setCacheSize(int size);
    void sayHello();
}
// 2. MBean 实现
public class Hello implements HelloMBean {
    private String name;
    private int cacheSize;
    @Override
    public String getName() { return name; }
    @Override
    public void setName(String name) { this.name = name; }
    @Override
    public int getCacheSize() { return cacheSize; }
    @Override
    public void setCacheSize(int size) {
        this.cacheSize = size;
        System.out.println("Cache size now set to: " + this.cacheSize);
    }
    @Override
    public void sayHello() {
        System.out.println("Hello, " + name + "!");
    }
}
// 3. 注册 MBean
public class JmxAgent {
    public static void main(String[] args) throws Exception {
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        ObjectName name = new ObjectName("com.example:type=Hello");
        Hello mbean = new Hello();
        mbs.registerMBean(mbean, name);
        System.out.println("Waiting for JMX client...");
        Thread.sleep(Long.MAX_VALUE);
    }
}

启动后,你可以用 VisualVM 或 JConsole 连接到这个 JVM,在 MBeans 标签页下找到 com.example -> Hello,就可以调用其方法、查看属性了。


总结与实战建议

工具/命令 主要用途 优点 缺点
jps 快速查找 Java 进程 ID 简单快速 信息量少
jstat 实时监控 GC 和内存使用 对性能影响小,数据实时 需要手动解析文本数据
jmap 生成堆快照,查看对象分布 是内存泄漏分析的起点 生成堆快照会导致应用 Stop-the-World
jstack 生成线程快照,分析死锁/CPU问题 定位线程问题的利器 快照是瞬间的,可能抓不到问题
jcmd 多功能命令,替代多个旧工具 功能强大,是未来的趋势 命令参数较多
VisualVM 全面的图形化监控 界面直观,功能集成度高 本地性能开销稍大
Eclipse MAT 深度分析堆转储文件 自动检测泄漏,功能最强大 需要学习使用,分析文件大时慢
JConsole 基础的图形化监控 轻量,随 JDK 安装 功能有限
JMX API 在应用中集成监控 灵活,可扩展,支持远程管理 需要编写代码

实战流程建议

  1. 发现问题:应用响应慢、CPU 占用高、频繁 Full GC。

    • 使用 tophtop 找到占用 CPU 高的 Java 进程的 PID。
    • 使用 jcmd <pid> Thread.print 或 VisualVM 查看线程,定位是哪个线程在消耗 CPU。
    • 使用 jcmd <pid> GC.heap_info 或 VisualVM 的 Visual GC 窗口,观察 GC 频率和耗时。
  2. 定位内存问题:怀疑内存泄漏(内存持续增长,OOM)。

    • 使用 jcmd <pid> GC.class_histogram 或 VisualVM 的 Sampler,观察对象数量是否异常。
    • 在问题发生前或发生时,使用 jcmd <pid> GC.heap_dump <file.hprof> 生成堆快照。
    • 使用 Eclipse MAT 打开 .hprof 文件,生成 Leak Suspects Report,直接定位泄漏根源。
  3. 持续监控:在生产环境进行常态化监控。

    • 在应用中集成 Micrometer、Dropwizard Metrics 等库,将 JVM 指标(GC、内存、线程)暴露给 Prometheus/Grafana 等监控系统。
    • 利用 JMX,通过编写自定义的 MBean 来暴露业务关键指标。
分享:
扫描分享到社交APP
上一篇
下一篇