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 下快速定位启动参数 | ❌ 否 | ❌ 否 |
✅ 建议优先使用 jcmd
和 jstat
组合拳:
- 用
jcmd
快速诊断当前堆状态 - 用
jstat
做周期性监控或集成进运维脚本
掌握这些命令后,再也不用靠猜来判断内存是否够用了。遇到 OOM 也能第一时间定位是堆空间不足还是 Metaspace 溢出,排查效率直接翻倍。