本文目录导读:

jstat 是 JDK 自带的一个轻量级命令行工具,专门用于监控 JVM 的 GC(垃圾回收)情况和类加载等信息,它非常适用于实时查看 GC 的频率、耗时和内存变化。
以下是关于如何使用 jstat 进行实时 GC 监控的详细指南和常用命令。
基础命令格式
jstat -<option> [-t] [-h<lines>] <vmid> [<interval>] [<count>]
-<option>:监控选项(GC 相关最常用的是-gc、-gcutil、-gccause)。-t:在输出结果第一列显示时间戳(从 JVM 启动到现在的秒数)。-h<lines>:每输出<lines>行后,重新打印一次表头。<vmid>:JVM 的进程 ID(可以使用jps -l或ps aux | grep java获取)。[<interval>]:采样间隔,单位是毫秒(ms)。1000表示每秒输出一次。[<count>]:采样的总次数,如果不指定,会一直持续输出直到手动停止(Ctrl+C)。
常用的 GC 监控选项
-gc:显示各个内存区域的使用情况、GC 次数和 GC 总耗时。-gcutil:显示各个内存区域的使用率(百分比,最常用)。-gccause:类似于-gcutil,但额外显示最近一次 GC 的原因。
实战命令示例
假设你的 Java 进程 PID 是 12345。
实时查看堆内存使用率(推荐)
每隔 1 秒显示一次各个分区的使用百分比,共显示 10 次。
jstat -gcutil -t 12345 1000 10
输出示例与字段解释:
| Timestamp | S0 | S1 | E | O | M | CCS | YGC | YGCT | FGC | FGCT | GCT |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 5 | 50 | 00 | 75 | 20 | 10 | 30 | 15 | 456 | 3 | 234 | 690 |
- Timestamp:JVM 已运行 320.5 秒。
- S0 / S1:Survivor 0 区 / Survivor 1 区的使用率(哪个为 0,哪个就是当前的空闲 To 区)。
- E:Eden 区(伊甸园)的使用率(%)。
- O:Old Gen(老年代)的使用率(%)。如果这个值持续增长且接近 100%,说明可能内存泄漏或需要更大的堆。
- M:Metaspace(元空间,JDK8+ 替代 PermGen)的使用率。
- CCS:Compressed Class Space(压缩类空间)使用率。
- YGC:Young GC(Minor GC)发生的总次数。
- YGCT:Young GC 累计总耗时(秒)。
- FGC:Full GC 发生的总次数。
- FGCT:Full GC 累计总耗时(秒)。
- GCT:所有 GC 累计总耗时(秒)。
详细查看堆内存容量变化
显示各个区域的当前容量、已使用量。
jstat -gc 12345 1000
输出包含:S0C(容量),S0U(已用),EC,EU,OC,OU,MC,MU 等。
单位通常是 KB。
查看最近一次 GC 的原因
结合 -gccause,它会显示 LGCC(上次 GC 原因)和 GCC(当前 GC 原因)。
jstat -gccause 12345 2000
输出额外字段:
- LGCC:
Allocation Failure(分配失败,常见触发 Young GC) - GCC:
No GC(当前没有 GC 发生),System.gc()(代码显式调用),G1 Evacuation Pause等。
如何解读这些数据(监控要点)
- Eden 区(E)频繁填满并触发 YGC:这是正常的,但若 YGC 次数增长过快,说明对象创建速度过快(代码可能产生了大量临时对象)。
- Survivor 区(S0/S1):
From和To区不断交替,如果一个 Survivor 区使用率长期很高(超过 80%),且对象频繁晋升老年代,说明 Survivor 空间可能过小。 - 老年代(O)持续上升:
YGC次数增加但O区仍然稳步上升,且最终触发FGC,这是老年代内存泄漏或存活对象过多的典型特征。FGC发生频繁且O区回收效果不大,通常意味着 Java 堆内存不足(需要 -Xmx 调大)或存在内存泄漏。
- GC 时间(YGCT / FGCT / GCT):
- YGC 时间:通常应在 10-50ms 级别,若单次 Young GC 耗时超过 100ms,可能说明对象存活率过高或 GC 线程分配不足。
- FGC 时间:非常关键,Full GC 是 Stop-the-World 的,如果单次 FGC 耗时超过 1 秒,会导致应用线程停顿、接口超时。这是生产环境最需要警惕的信号。
高级监控技巧
结合 Watch 命令实现动态监控
在 Linux 下,可以配合 watch 命令每隔几秒刷新一次(比手动 jstat 更直观):
watch -n 2 'jstat -gcutil 12345'
监控新生代对象晋升速率(间接估算)
观察一段时间内老年代增长量 (OU_end - OU_start) 除以时间间隔,如果增长速率很快,说明大量对象迅速进入老年代,可能是 Survivor 空间设置不足或者对象本身太大。
输出到文件以便事后分析
jstat -gcutil -t 12345 1000 3600 > gc_monitor.log &
这会将接下来 1 小时(3600 次 * 1秒/次)的 GC 数据记录到文件,用于后期可视化分析。
适用场景与局限
- 优点:JDK 自带、轻量、无需任何配置、几乎不消耗系统资源。
- 缺点:
- 只能看到结果(耗时、次数),看不到 GC 过程中的细节(如 GC Roots 扫描耗时、各阶段停顿)。
- 不适合分析堆外内存、线程问题或锁竞争。
如果你需要更深入的 GC 日志分析,建议开启 JVM GC 日志(-Xlog:gc*)或使用 jcmd 或专业工具(如 GCeasy, GCEasy.io 分析 GC 日志文件)。
总结一句话:jstat -gcutil 是排查线上 JVM GC 问题的“第一板斧”,可以快速定位老年代占用过高或 Full GC 频繁的问题。