You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将JVM C2编译器统计数据暴露至JMX?

JMX暴露C2编译、去优化及jstat全量编译指标实现方案

原生CompilationMXBean确实只提供总编译时长一个核心指标,完全覆盖不了日常监控需求,下面的方案全部基于JDK内置API实现,不需要依赖第三方组件、不需要修改JDK源码,生产环境可用。

核心实现逻辑

jstat展示的所有编译统计、C2编译计数、去优化相关数据,本身就存在JVM进程内存的PerfData计数器里,只是没有默认注册成JMX可访问的MBean,我们只需要把这些数据读出来,注册到平台MBeanServer即可。


1. 指标数据源说明

1.1 计数类指标(和jstat数据源完全一致)

直接通过JDK自带的jvmstat包读取Perf计数器,和jstat读取逻辑100%对齐,没有数据偏差,常用指标对应的计数器key如下:

  • C2编译器编译方法总数:读取sun.ci.compilerThread.2.compiles(分层编译开启时,tier4层级编译数即为C2编译数,可通过sun.ci.tiered.compiles.tier4获取)
  • 去优化总次数:读取sun.ci.deoptimization.total,还可按需细分重编译触发的去优化(sun.ci.deoptimization.recompiled)、异常陷阱触发的去优化(sun.ci.deoptimization.trapped)
  • jstat -compiler输出的全量字段对应关系:
    • Compiled(总编译数):java.ci.totalCompiles
    • Failed(编译失败数):sun.ci.compilation.failures
    • Invalid(无效编译数):sun.ci.compilation.invalid
    • Time(总编译时长):java.ci.totalCompilationTime(即原生MBean暴露的指标)
    • FailedType(最近失败类型):sun.ci.lastFailedType
    • FailedMethod(最近失败方法):sun.ci.lastFailedMethod

读取Perf计数器的核心代码示例(JDK8+都支持):

import sun.jvmstat.monitor.MonitoredHost;
import sun.jvmstat.monitor.MonitoredVm;
import sun.jvmstat.monitor.VmIdentifier;

public long getPerfLongValue(String counterName) throws Exception {
    String pid = String.valueOf(ProcessHandle.current().pid());
    MonitoredHost host = MonitoredHost.getMonitoredHost(new VmIdentifier(pid));
    MonitoredVm vm = host.getMonitoredVm(new VmIdentifier(pid));
    try {
        return (long) vm.findByName(counterName).getValue();
    } finally {
        vm.detach();
    }
}

1.2 编译/去优化方法名采集

不需要手写JVMTI Agent,直接用内置JFR事件采集即可,生产环境开销低于1%:

  • 启动参数加-XX:StartFlightRecording:settings=profile,jdk.Compilation#enabled=true,jdk.Deoptimization#enabled=true
  • 代码里定期轮询JFR记录的jdk.Compilation、jdk.Deoptimization事件,提取事件里的方法签名、编译层级、去优化原因字段
  • 建议只保留最近1000条记录即可,不要全量存储避免内存占用过高

2. 注册自定义MBean

把上面采集到的所有指标封装成标准MBean,注册到平台MBeanServer即可通过JMX访问:

MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("com.custom:type=JvmCompileMetrics");
CompileMetricsMBean mbean = new CompileMetrics(); // 自行实现的指标持有类
mbs.registerMBean(mbean, name);

注册完成后,就可以通过JMX客户端拉取C2编译数、去优化数、对应方法名、jstat全量编译统计所有指标了。


注意事项

  • 分层编译开启时不要直接把总编译数算成C2编译数,一定要按编译层级过滤,tier4才是C2生成的机器码
  • JFR采集方法名时记得过滤掉JDK内部方法,避免无效数据占空间
  • 如果是JDK8u之前的版本,需要把tools.jar加到classpath才能使用jvmstat包

内容的提问来源于stack exchange,提问作者greg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 22:15:49