用 jstat -gc <pid> 2000 每2秒刷新观察 YGCT、FGCT、EU、OU 等指标,连续监控才能识别 GC 频率异常与堆占用趋势,单次结果无诊断价值。

怎么用 jstat 快速看 GC 频率和堆占用
jstat 是最轻量、最常驻的 JVM 监控命令,不需要额外启动服务,也不依赖 JMX 开启。它直接读取 JVM 进程的内部统计结构,适合在生产环境快速诊断内存压力。
常见错误是只跑一次就下结论——jstat 的价值在于连续观察。比如发现 YGC 每秒 2–3 次,但没对比历史 baseline,容易误判为“正常”;实际可能刚从每分钟 1 次恶化而来。
- 查进程 ID:
jps -l或ps aux | grep java - 每 2 秒刷新一次 GC 统计:
jstat -gc <pid> 2000 - 重点关注列:
YGCT(年轻代 GC 总耗时)、FGCT(Full GC 总耗时)、EU(Eden 使用量)、OU(老年代使用量) - 如果
OU持续上涨且FGCT增加,说明对象正在堆积进老年代,不是 GC 配置问题就是内存泄漏
VisualVM 连不上远程 JVM 怎么办
VisualVM 默认只能连本地 JVM,连远程时失败最常见原因是:JMX 端口未暴露 + 缺少安全参数。它不像 jstat 那样走本地共享内存,必须走网络通信。
别直接开 -Dcom.sun.management.jmxremote 就跑,Java 8u191+ 默认禁用不带认证的远程 JMX,否则会报错:java.rmi.ConnectException: Connection refused to host
立即学习“Java免费学习笔记(深入)”;
- 启动 Java 应用时加这些参数(注意替换
<ip>和端口):-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.rmi.port=9999 -Dcom.sun.management.jmxremote.host=<ip> -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false - 确保防火墙放行该端口:
iptables -I INPUT -p tcp --dport 9999 -j ACCEPT(Linux) - VisualVM 中添加远程主机后,右键 → “Add JMX Connection”,填
<ip>:9999,不要勾选“Use SSL” - 如果应用跑在 Docker 里,记得用
--network=host或显式映射端口,且-Dcom.sun.management.jmxremote.host不能写localhost
jstat 和 VisualVM 看到的堆大小为什么对不上
这不是 bug,是统计口径差异。jstat 显示的是 JVM 当前内存池的实时用量(如 EU, SU, OU),而 VisualVM 的“Heap”图表默认显示的是 used + committed 的组合视图,并受 GC 触发时机影响——它采样的是 GC 后的快照,而 jstat 是持续轮询。
更关键的是:VisualVM 如果连接的是 JDK 8,某些内存池(如 Metaspace)可能被归入“Non-heap”,而 jstat -gc 默认不显示 Metaspace,得用 jstat -gccapacity 或 jstat -gcmetacapacity 单独查。
- 查完整内存池分布:
jstat -gc <pid>(基础 GC 数据)、jstat -gcmetacapacity <pid>(元空间容量)、jstat -compiler <pid>(JIT 编译状态) - VisualVM 中右键图表 → “Show Heap Dump” 只能看瞬间堆快照,不能替代
jstat的趋势观察 - 两者都看不到 native memory(如 DirectByteBuffer 分配),这类泄漏得靠
pmap -x <pid>或jcmd <pid> VM.native_memory summary
VisualVM 插件装了却没反应?别碰“Visual GC”插件
“Visual GC” 插件在 JDK 9+ 已彻底失效,它依赖已移除的 com.sun.tools.jvmstat 包。装了也白装,界面空白或报 NoClassDefFoundError。这是最容易踩的兼容性坑。
真正可用的替代方案只有两个:一是用内置的 “Monitor” 标签页(含堆/线程/类加载曲线),二是装 “VisualVM-MBeans” 插件后手动查 java.lang:type=Memory MBean 的 Usage 属性。
- JDK 8 环境可继续用 Visual GC,但需确认 JDK 路径正确(VisualVM → Tools → Options → Java → JDKs)
- JDK 11+ 用户请直接放弃所有第三方 GC 可视化插件,专注用
jstat+jcmd <pid> VM.native_memory+ GC 日志(-Xlog:gc*:file=gc.log:time) - VisualVM 自带的 “Sampler” 标签页对 CPU/内存采样有效,但采样精度不如
async-profiler,线上慎用
真正难的是把 jstat 的数字变化和代码逻辑对应起来——比如 OU 上涨时,到底是某个缓存没设淘汰策略,还是某次 DB 查询返回了百万级 List。工具只是放大镜,不是诊断书。



















