1. 概述

在实际开发和线上问题排查中,我们经常需要快速查看一个正在运行的 Java 应用的堆内存使用情况。本文将介绍几种简单粗暴但非常实用的命令行方式,帮助你精准掌握 JVM 堆和元空间(Metaspace)的实时状态。

这些方法适用于已有一定 JVM 调优经验的开发者,避免盲目猜测内存瓶颈,真正做到“有图有真相”。


2. 使用 jcmd 查看堆信息

推荐方式之一:jcmd 是 Oracle JDK 提供的强大诊断工具,可以直接输出 JVM 的详细堆信息。

首先,使用 jps 找到目标 Java 进程的 PID:

$ jps -l
73170 org.jetbrains.idea.maven.server.RemoteMavenServer36
4309  quarkus.jar
12070 sun.tools.jps.Jps

如上所示,我们的 Quarkus 应用 PID 为 4309。接下来执行:

jcmd 4309 GC.heap_info

输出示例:

4309:
 garbage-first heap   total 206848K, used 43061K
  region size 1024K, 43 young (44032K), 3 survivors (3072K)
 Metaspace       used 12983K, capacity 13724K, committed 13824K, reserved 1060864K
  class space    used 1599K, capacity 1740K, committed 1792K, reserved 1048576K

输出解读(G1 GC 场景):

  • 堆总大小:202MB(206848K),已使用 42MB(43061K)
  • G1 区域大小:每个 region 为 1MB,当前有 43 个年轻代 region,3 个 survivor 区
  • Metaspace
    • 已使用 12.7MB,容量 13.4MB,最大可扩展至 1GB
    • committed 内存 13.5MB,表示 JVM 已向操作系统申请并保证可用的部分
  • Class Space:用于存储类元数据,当前使用约 1.6MB

⚠️ 注意:不同 GC 算法输出格式差异较大。例如切换到 ZGC 后:

# 启动参数:-XX:+UnlockExperimentalVMOptions -XX:+UseZGC

输出变为:

ZHeap           used 28M, capacity 200M, max capacity 1024M
Metaspace       used 21031K, capacity 21241K, committed 21504K, reserved 22528K

而 CMS GC(如老版本 IntelliJ IDEA)则显示为经典的分代结构:

par new generation   total 613440K, used 114299K
  eden space 545344K,  18% used
  from space 68096K,  16% used
  to   space 68096K,   0% used
 concurrent mark-sweep generation total 1415616K, used 213479K
 Metaspace       used 423107K, capacity 439976K, committed 440416K, reserved 1429504K

可以看到明显的新生代(Eden + Survivor)和老年代(CMS Generation)划分。


3. 使用 jstat 实时监控 GC 状态

适合脚本化监控或持续观察内存变化趋势。

jstat 是另一个 JDK 自带的轻量级性能统计工具,特别适合做定时采样。

执行命令:

$ jstat -gc 4309
S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     
0.0    0.0    0.0    0.0   129024.0  5120.0   75776.0    10134.6   20864.0
MU      CCSC   CCSU     YGC     YGCT    FGC    FGCT     CGC    CGCT     GCT
19946.2 2688.0 2355.0    2      0.007    1      0.020    0     0.000     0.027

关键列说明:

列名 含义
S0C/S1C Survivor0/1 区容量(KB)
S0U/S1U Survivor0/1 区已使用(KB)
EC / EU Eden 区容量与使用量
OC / OU 老年代容量与使用量
MC / MU Metaspace 容量与使用量
CCSC / CCSU 压缩类空间(Compressed Class Space)
YGC / YGCT 新生代 GC 次数与总耗时(秒)
FGC / FGCT Full GC 次数与耗时
CGC / CGCT 并发 GC 次数与耗时(如 G1 Concurrent Cycle)
GCT 所有 GC 总耗时

其他常用选项:

  • -gccapacity:显示各区域最大/最小容量
  • -gcutil:仅显示各区域使用百分比(更适合监控图表)
  • -gccause:同 -gcutil,但附加上次 GC 的触发原因(如 Allocation Failure)

📌 小技巧:结合 watch 命令可实现动态刷新:

watch -n 1 'jstat -gcutil 4309'

每秒刷新一次 GC 使用率,排查内存泄漏时非常直观。


4. 从启动参数获取堆配置

只能看到初始配置,无法反映运行时真实内存占用。但仍有一定参考价值。

如果应用启动时设置了 -Xms-Xmx,可以通过以下方式查看原始配置:

方法一:jps -lv

$ jps -lv
4309 quarkus.jar -Xms200m -Xmx1g

方法二:jcmd <pid> VM.command_line

$ jcmd 4309 VM.command_line
4309:
VM Arguments:
jvm_args: -Xms200m -Xmx1g
java_command: quarkus.jar
java_class_path (initial): quarkus.jar
Launcher Type: SUN_STANDARD

方法三:ps 查看进程命令行

$ ps -ef | grep quarkus
user1  4309  ... java -Xms200m -Xmx1g -jar quarkus.jar

方法四:读取 /proc/<pid>/cmdline

Linux 系统下直接访问虚拟文件系统:

$ cat /proc/4309/cmdline
java -Xms200m -Xmx1g -jar quarkus.jar

⚠️ 踩坑提醒:这些方法只能看到启动时的 -Xms-Xmx 设置,并不能反映当前 JVM 实际提交的内存(committed memory),也无法看到 Metaspace 动态扩容情况。因此仅适合做初步判断。


5. 总结

工具 适用场景 是否实时 是否依赖 GC 类型
jcmd GC.heap_info 快速查看完整堆结构 ✅ 是 ✅ 是(输出格式不同)
jstat -gc 脚本化监控、性能采集 ✅ 是 ❌ 否(统一格式)
jps -lv / VM.command_line 查看初始配置 ❌ 否 ❌ 否
/proc/<pid>/cmdline Linux 下快速定位启动参数 ❌ 否 ❌ 否

建议优先使用 jcmdjstat 组合拳

  • jcmd 快速诊断当前堆状态
  • jstat 做周期性监控或集成进运维脚本

掌握这些命令后,再也不用靠猜来判断内存是否够用了。遇到 OOM 也能第一时间定位是堆空间不足还是 Metaspace 溢出,排查效率直接翻倍。


原始标题:Command-Line Tools to Find the Java Heap Size