JDK jstat 命令详解:基于 jvmstat 框架的 JVM 实时统计监控
发布时间:2026/9/13 23:51:58 作者:尧图编辑部 阅读量:1,286

JDK jstat 命令详解基于 jvmstat 框架的 JVM 实时统计监控【免费下载链接】jdkJDK main-line development https://openjdk.org/projects/jdk项目地址: https://gitcode.com/GitHub_Trending/jd/jdk本文以 JDK 仓库中 jstat 官方手册页 为主体系统讲解jstat命令的完整参数、全部 11 个统计选项及其列含义、虚拟机标识符vmid的构成与远程监控方式并深入 jdk.jcmd 模块 的源码剖析这些选项背后由jstat_options描述文件驱动的表格式输出机制。读完本文你将能够针对本地与远程 JVM 进行 GC、类加载、JIT 编译等维度的实时采样监控并理解每列数据的来源与输出格式的实现原理。1. jstat 的定位与前提约束jstat用于显示受插桩的 Java HotSpot 虚拟机的性能统计信息目标 JVM 通过虚拟机标识符vmid指定。它与 Unix 平台的vmstat、iostat、mpstat等stat系列工具一脉相承——从 Jstat.java 的类注释可以看出其设计灵感正来源于这套工具。手册页中有多条重要的前提约束直接决定使用方式实验性命令手册明确标注 This command is experimental and unsupported该命令是实验性且不受支持的。接口不稳定所有选项及其功能在后续版本中都可能变更或移除。手册特别告诫不要编写脚本去解析jstat的输出因为其格式在未来版本中可能变化如果确实要解析就要为后续版本做修改准备。临时目录一致性如果目标 JVM 以非默认的临时文件位置启动jstat必须使用相同的临时文件位置才能与其通信——这涉及java命令的-XX:AltTempDir选项。jstat 与目标 JVM 通过本地文件交换统计信息目录不一致则无法附着。2. 命令语法总览手册页给出的标准用法有两种形式jstat generalOptions jstat outputOptions [-t] [-h lines] vmid [interval [count]]参数说明完整继承自手册页参数说明generalOptions单个通用命令行选项见下文通用选项outputOptions由-options选项报告的一个或多个输出选项由一个statOption加上可选的-t、-h、-J选项组成statOption必须放在最前面-t在输出的第一列显示时间戳列。时间戳是目标 JVM 启动以来的时间秒-h n每n个采样输出行显示一次列标题n为正整数。默认值为0即只在第一行数据前显示列标题vmid虚拟机标识符指示目标 JVM语法见下文interval采样间隔支持s秒或ms毫秒两种单位默认单位是毫秒必须是正整数。指定后jstat按该间隔产生输出count采样次数。默认值为无穷大即持续显示统计信息直到目标 JVM 终止或jstat命令被终止CtrlC从 Arguments.java 的toMillis方法可以看到间隔解析实现只有ms与s两种合法后缀缺省按毫秒处理非法单位会抛出 Unknown time unit 异常。因此jstat -gcutil pid 250 7中的250表示 250 毫秒间隔想表达秒级间隔应写1s而非1000两种写法均可。一个手册未直接展开、但源码确认的默认行为值得注意在 Arguments.java 中当interval与count都未给出时默认值被设为count 1、interval 0即只采集一次快照后退出。所以count 默认为无穷大成立的前提是你给出了interval而未给出count。2.1 通用选项General Options指定任意一个通用选项后就不能再指定其他选项或参数选项说明-help显示帮助信息-?、-h、--help等效见 Arguments.java-options显示当前平台安装支持的静态选项列表即所有 statOption2.2 输出选项的通用修饰项如果不指定通用选项就可以使用输出选项。输出选项决定输出的内容与格式由单个statOption加上任意其他输出选项-h、-t、-J构成statOption必须位于最前。输出格式化为空格分隔的表格带有标题头行用-h设置标题显示的频率不同选项之间同名列的表头名称保持一致——一般而言若两个选项提供同名列则两列的数据源相同-t选项使输出第一列出现Timestamp列其值为目标 JVM 启动以来经过的秒数。时间戳的分辨率受多种因素影响在系统负载较高时可能因线程调度延迟而波动用interval与count参数分别控制多久输出一次和输出多少次-J javaOption把javaOption传递给 Java 应用启动器。例如-J-Xms48m把启动内存设为 48 MB。完整选项列表见java命令的手册页。3. 虚拟机标识符vmidvmid字符串的语法对应 URI 的语法[protocol:][//]lvmid[hostname[:port][/servername]]它可以从表示本地 JVM 的简单整数到指定通信协议、端口号及实现特定值的复杂构造。各组成部分组成说明protocol通信协议。若省略protocol且未指定主机名则默认为平台相关的优化的本地协议若省略protocol但指定了主机名则默认协议为rmilvmid目标 JVM 的本地虚拟机标识符是平台相关的值用于在系统上唯一标识一个 JVM是 vmid 中唯一必需的组件。lvmid通常是但不必然是目标 JVM 进程的操作系统进程 ID。可以用jps命令确定lvmid前提是目标 JVM 不在独立的 docker 实例中运行也可以在 Linux 和 macOS 上用ps命令、在 Windows 上用任务管理器查看hostname指示目标主机的主机名或 IP 地址。省略时目标为主机自身port与远程服务器通信的默认端口。若省略hostname或protocol指定的是优化的本地协议则port被忽略。对于默认的rmi协议port 指示远程主机上rmiregistry的端口号若省略port且protocol为rmi则使用 rmiregistry 的默认端口1099servername处理方式取决于实现。优化的本地协议下忽略该字段rmi协议下它表示远程主机上 RMI 远程对象的名称4. stat 选项与输出列完整参考以下是手册页中每个 statOption 输出的列含义汇总共 11 个选项。可用-options通用选项查看特定平台安装实际支持的列表因为选项集合会随平台与版本变化。4.1-class类加载器统计列含义Loaded已加载的类数量Bytes已加载的 KB 数类占用的字节数Unloaded已卸载的类数量Bytes已卸载的 KB 数与上一列同名含义不同按顺序区分Time执行类加载与卸载操作所花费的时间4.2-compilerJIT 编译器统计列含义Compiled已执行的编译任务数Failed失败的编译任务数Invalid被失效invalidate的编译任务数Time执行编译任务所花费的时间FailedType最近一次失败编译的编译类型FailedMethod最近一次失败编译的类名与方法4.3-gc垃圾回收堆统计列含义S0C当前 survivor 空间 0 容量KBS1C当前 survivor 空间 1 容量KBS0Usurvivor 空间 0 使用量KBS1Usurvivor 空间 1 使用量KBEC当前 eden 空间容量KBEUeden 空间使用量KBOC当前 old 空间容量KBOUold 空间使用量KBMCMetaspace 已提交大小KBMUMetaspace 使用量KBCCSC压缩类空间已提交大小KBCCSU压缩类空间已使用大小KBYGC年轻代 GC 事件数YGCT年轻代 GC 耗时FGC完整 GC 事件数FGCT完整 GC 耗时GCTGC 总耗时4.4-gccapacity各代与空间容量列含义NGCMN年轻代最小容量KBNGCMX年轻代最大容量KBNGC当前年轻代容量KBS0C当前 survivor 空间 0 容量KBS1C当前 survivor 空间 1 容量KBEC当前 eden 空间容量KBOGCMN老年代最小容量KBOGCMX老年代最大容量KBOGC当前老年代容量KBOC当前 old 空间容量KBMCMNMetaspace 最小容量KBMCMXMetaspace 最大容量KBMCMetaspace 已提交大小KBCCSMN压缩类空间最小容量KBCCSMX压缩类空间最大容量KBCCSC压缩类空间已提交大小KBYGC年轻代 GC 事件数FGC完整 GC 事件数4.5-gcutilGC 统计摘要百分比视角列含义S0survivor 空间 0 使用量占当前容量的百分比S1survivor 空间 1 使用量占当前容量的百分比Eeden 空间使用量占当前容量的百分比Oold 空间使用量占当前容量的百分比MMetaspace 使用量占当前容量的百分比CCS压缩类空间使用百分比YGC年轻代 GC 事件数YGCT年轻代 GC 耗时FGC完整 GC 事件数FGCT完整 GC 耗时GCTGC 总耗时4.6-gccauseGC 摘要 回收原因显示与-gcutil相同的 GC 统计摘要但额外包含最近一次 GC 事件以及如适用当前 GC 事件的原因在-gcutil各列之外增加列含义LGCC最近一次 GC 的原因GCC当前 GC 的原因4.7-gcnew年轻代统计列含义S0C/S1C当前 survivor 空间 0 / 1 容量KBS0U/S1Usurvivor 空间 0 / 1 使用量KBTT当前老化阈值Tenuring thresholdMTT最大老化阈值DSS期望的 survivor 大小KBEC当前 eden 空间容量KBEUeden 空间使用量KBYGC年轻代 GC 事件数YGCT年轻代 GC 耗时4.8-gcnewcapacity年轻代空间大小列含义NGCMN/NGCMX/NGC年轻代最小 / 最大 / 当前容量KBS0CMX/S0Csurvivor 空间 0 最大 / 当前容量KBS1CMX/S1Csurvivor 空间 1 最大 / 当前容量KBECMX/ECeden 空间最大 / 当前容量KBYGC年轻代 GC 事件数FGC完整 GC 事件数4.9-gcold老年代与 Metaspace 统计列含义MCMetaspace 已提交大小KBMUMetaspace 使用量KBCCSC压缩类空间已提交大小KBCCSU压缩类空间已使用大小KBOC当前 old 空间容量KBOUold 空间使用量KBYGC年轻代 GC 事件数FGC完整 GC 事件数FGCT完整 GC 耗时GCTGC 总耗时4.10-gcoldcapacity老年代容量列含义OGCMN/OGCMX/OGC老年代最小 / 最大 / 当前容量KBOC当前 old 空间容量KBYGC/FGC年轻代 / 完整 GC 事件数FGCT/GCT完整 GC 耗时 / GC 总耗时4.11-gcmetacapacityMetaspace 大小列含义MCMN/MCMXMetaspace 最小 / 最大容量KBMCMetaspace 已提交大小KBCCSMN/CCSMX压缩类空间最小 / 最大容量KBYGC/FGC年轻代 / 完整 GC 事件数FGCT/GCT完整 GC 耗时 / GC 总耗时4.12-printcompilation最近编译方法统计列含义Compiled最近一次编译方法时的累计编译任务数Size最近一次编译方法的字节码字节数Type最近一次编译方法的编译类型Method标识最近一次编译方法的类名与方法名。类名用斜杠/而非点.作为命名空间分隔符两字段的格式与 HotSpot 的-XX:PrintCompilation选项一致5. 手册页四个实战示例以下示例均来自手册页演示监控一个lvmid为 21891 的本地 JVM。5.1-gcutil采样观察一次 Young GC该示例附着到 lvmid 21891以 250 毫秒间隔采集 7 个样本jstat -gcutil 21891 250 7 S0 S1 E O M CCS YGC YGCT FGC FGCT GCT 0.00 97.02 70.31 66.80 95.52 89.14 7 0.300 0 0.000 0.300 0.00 97.02 86.23 66.80 95.52 89.14 7 0.300 0 0.000 0.300 0.00 97.02 96.53 66.80 95.52 89.14 7 0.300 0 0.000 0.300 91.03 0.00 1.98 68.19 95.89 91.24 8 0.378 0 0.000 0.378 91.03 0.00 15.82 68.19 95.89 91.24 8 0.378 0 0.000 0.378 91.03 0.00 17.80 68.19 95.89 91.24 8 0.378 0 0.000 0.378 91.03 0.00 17.80 68.19 95.89 91.24 8 0.378 0 0.000 0.378手册页对该输出的解读第 3、4 个样本之间发生了一次年轻代收集耗时 0.078 秒YGCT 从 0.300 增至 0.378对象从 eden 空间E晋升到 old 空间O使 old 空间使用率从 66.80% 上升到 68.19%。收集前 survivor 空间使用率为 97.02%收集后降为 91.03%注意 S0/S1 两个 survivor 空间发生了翻转。5.2-h3重复列标题该示例以 250 毫秒间隔采样并用-gcnew输出同时用-h3使列标题每 3 行数据后重新输出一次jstat -gcnew -h3 21891 250 S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT 64.0 64.0 0.0 31.7 31 31 32.0 512.0 178.6 249 0.203 64.0 64.0 0.0 31.7 31 31 32.0 512.0 355.5 249 0.203 64.0 64.0 35.4 0.0 2 31 32.0 512.0 21.9 250 0.204 S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT 64.0 64.0 35.4 0.0 2 31 32.0 512.0 245.9 250 0.204 64.0 64.0 35.4 0.0 2 31 32.0 512.0 421.1 250 0.204 64.0 64.0 0.0 19.0 31 31 32.0 512.0 84.4 251 0.204 S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT 64.0 64.0 0.0 19.0 31 31 32.0 512.0 306.7 251 0.204手册页解读第 2、3 个样本之间发生了一次年轻代 GC耗时 0.001 秒YGCT 从 0.203 增至 0.204。该次收集发现活跃数据量足够多若 survivor 空间 0 的使用量S0U超过期望 survivor 大小DSS于是对象被晋升到老年代此输出中不可见老化阈值 TT 从 31 被降到 2。第 5、6 个样本之间又发生一次收集这次存活对象很少TT 恢复回 31。这正是-gcnew相比-gcutil的额外价值能观察到自适应年龄阈值TT/MTT/DSS的动态变化。5.3-t为每个样本加时间戳该示例附着到 lvmid 21891以 250 毫秒间隔采集 3 个样本-t选项使第一列出现 Timestamp。该列报告目标 JVM 启动以来经过的秒数。同时-gcoldcapacity输出显示 old 代容量OGC与 old 空间容量OC随堆扩张而增长第 81 次完整 GC 后OGC 已从 11,696 KB 增长到 13,820 KB而该代与空间的最大容量为 60,544 KBOGCMX仍有扩张余量。Timestamp OGCMN OGCMX OGC OC YGC FGC FGCT GCT 150.1 1408.0 60544.0 11696.0 11696.0 194 80 2.874 3.799 150.4 1408.0 60544.0 13820.0 13820.0 194 81 2.938 3.863 150.7 1408.0 60544.0 13820.0 13820.0 194 81 2.938 3.8635.4 远程 JVM 监控该示例附着到名为remote.domain的系统上 lvmid 40496 的 JVM使用-gcutil选项每秒采样一次并无限持续jstat -gcutil 40496remote.domain 1000 ... output omitted手册页解释将 lvmid 与远程主机名组合构造出 vmid40496remote.domain。由于指定了主机名而省略了协议默认采用rmi协议与远程主机上的默认jstatd服务器通信。jstatd服务器通过remote.domain上绑定到 rmiregistry 默认端口1099的rmiregistry命令定位。远程监控的前提是在远端先启动jstatd由 JDK 仓库中的jdk.jstatd模块提供见 src/jdk.jstatd。6. 源码剖析stat 选项背后的实现机制手册页描述的每个 statOption 在实现上都不是硬编码的表格而是由描述文件 解析器 表达式求值器驱动的通用框架。这条链路让 jstat 具备了选项可扩展、列可定义的结构。6.1 入口与整体流程Jstat.java 的main方法流程非常清晰new Arguments(args)解析命令行失败则打印 usage 并退出-help→ 打印用法-options→ 用OptionLister打印所有已定义的选项其余情况分三条路径logNames()列出计数器名、logSnapShot()快照、logSamples()周期采样。核心采样路径 logSamples() 的关键步骤通过MonitoredHost.getMonitoredHost(vmId)获得监控宿主本地文件协议或 RMI 协议正对应手册中 vmid 的协议语义再getMonitoredVm(vmId, interval)附着到目标 JVM若命令携带特殊选项statOption构造OptionOutputFormatter(monitoredVm, format)否则按名称模式匹配计数器走RawOutputFormatter注册shutdown hook响应用户中断CtrlC并注册HostListener监听目标 JVM 的终止/断连事件——这正是手册所说count 默认为无穷大时直到目标 JVM 终止或 jstat 被终止才停止的实现最后调用logger.logSamples(formatter, headerRate, interval, count, out)执行采样循环headerRate即-h参数控制的标题行重复频率。6.2 选项定义文件jstat_optionsjstat -gcutil中的列布局定义在资源文件 jstat_options 中格式是每列一个column块含表头、数据表达式、比例、对齐、宽度、格式。例如timestamp选项option timestamp { column { header ^Timestamp data ((jstat.timestamp - sun.rt.createVmBeginTime) / 1000) scale sec align right width 15 format 0.0 } }由此可以确认手册页的表述Timestamp 列就是(当前时间 - 目标 VM 创建时间) / 1000单位秒scale sec宽度 15保留 1 位小数——与示例输出150.1 / 150.4 / 150.7完全吻合。Timestamp.java 中jstat.timestamp符号的取值就是System.currentTimeMillis()。再看-class与-compiler选项的定义jstat_options 第 37–119 行附近Loadedjava.cls.loadedClasses java.cls.sharedLoadedClasses即同时统计应用类与共享类如 CDS/元数据共享Bytes列使用scale K所以输出是 KB——对应手册中Number of KB loadedTime列是sun.cls.time / sun.os.hrt.frequency即把硬件时钟拍数换算成秒-compiler的Compiled/Failed/Invalid分别映射到sun.ci.totalCompiles / sun.ci.totalBailouts / sun.ci.totalInvalidatesTime为java.ci.totalTime / sun.os.hrt.frequency。这说明手册页中两个选项提供同名列时数据源相同的原则在定义文件层面天然成立列的语义由符号counter唯一决定。Arguments.optionsSources() 揭示了选项文件的加载顺序这也是手册-options显示特定平台安装的选项列表的原因~/.jvmstat/jstat_options用户目录下的用户自定义/覆盖文件jdk.jcmd 模块内置资源sun/tools/jstat/resources/jstat_options若设置了-Djstat.showUnsupported还会追加jstat_unsupported_options。从源码结构看用户可以在~/.jvmstat/jstat_options中定义自定义选项或覆盖内置列这是该框架可定制的体现而jstat_unsupported_options则承载了在部分平台上不受支持、默认隐藏的列。6.3 从解析到输出OptionFormat 的求值链OptionFinder 依次尝试各 optionsSources用Parser把文本解析为OptionFormat列格式对象当-t开启时它会把timestamp选项中的列插入为第一列insertSubFormat(0, ...)——这正是-t实现为在首列插入时间戳列而非另开输出通道的机制若某个 statOption 在上述来源中都找不到定义Arguments 会抛出Unknown option: -name所以选项是否可用完全由选项文件决定与手册所有选项可能随版本变更或移除的告诫一致OptionOutputFormatter 在构造时通过ExpressionResolver将表达式中的符号解析为对MonitoredVm计数器的实际引用getHeader()/getRow()分别在HeaderClosure/RowClosure中渲染表头行与数据行——对应输出格式化为空格分隔表格的行为。6.4 手册未列出的源码级选项Arguments.java 的帮助信息注释中还列出了一些未公开文档化undocumented的选项-list [vmid]列出计数器名、-snap vmid以 namevalue 形式输出计数器快照、-name pattern输出匹配模式的计数器、-a/-d升序/降序排序、-v-snap的冗长输出、-constants连同常量一起输出、-strings输出字符串型计数器。另有-Djstat.debug与-Djstat.showUnsupported两个调试开关见 Arguments.java。这些属于实现细节不在手册支持的接口范围内稳定性不作保证仅供深入排查时参考。7. 使用建议小结结合手册页与源码证据实践中使用 jstat 的建议选择观察维度GC 使用率趋势用-gcutil最常用要看绝对 KB 值用-gc要定位 GC 触发原因加-gccause调年轻代参数时观察-gcnew的 TT/DSS 自适应行为观察堆扩张用-gcoldcapacity/-gccapacity诊断类加载器泄漏用-class关注Unloaded是否停滞观察 JIT 用-compiler与-printcompilation。控制输出节奏-t加时间戳便于对账-h n在长时间滚动输出时保持可读性interval缺省按毫秒跨秒请写1000或1s不指定interval时只取一次快照。保持临时目录一致目标 JVM 若使用了AltTempDirjstat 侧必须一致否则无法附着。远程场景lvmidhostname形式走 RMI 协议远端需运行jstatd且 rmiregistry 默认为 1099 端口容器内运行时jps可能看不到目标需直接进入容器或从外部用正确的 lvmid 访问。不要硬编码解析输出手册明确输出格式可能变化如需程序化处理 JVM 统计应优先考虑 JMX API 等稳定接口而把 jstat 定位为交互式诊断工具。8. 参考路径文件说明src/jdk.jcmd/share/man/jstat.md本文主体依据的 jstat 手册页源文件src/jdk.jcmd/share/classes/sun/tools/jstat/Jstat.javajstat 入口与采样主循环src/jdk.jcmd/share/classes/sun/tools/jstat/Arguments.java命令行解析、interval 单位、默认值、选项文件来源src/jdk.jcmd/share/classes/sun/tools/jstat/resources/jstat_options全部 stat 选项的列定义文件src/jdk.jcmd/share/classes/sun/tools/jstat/OptionFinder.java选项解析与 -t 时间戳列注入src/jdk.jcmd/share/classes/sun/tools/jstat/OptionOutputFormatter.java表头/数据行的格式化输出src/jdk.jcmd/share/classes/sun/tools/jstat/JStatLogger.java采样循环与日志输出说明本文基于 JDK main 分支仓库当前内容编写jstat为实验性命令其选项集合与输出列以实际版本中jstat -options的打印结果为准。【免费下载链接】jdkJDK main-line development https://openjdk.org/projects/jdk项目地址: https://gitcode.com/GitHub_Trending/jd/jdk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考