JMH必须通过maven插件生成benchmark jar运行,不能直接IDEA运行main;需配置jmh-maven-plugin、启用注解处理器、用ForkedMain启动或执行mvn package后java -jar target/benchmarks.jar。

为什么直接加 jmh-core 依赖跑不起来
IDEA 里新建模块后只加了 jmh-core,一运行就报 NoClassDefFoundError: org/openjdk/jmh/runner/Runner 或直接提示 “找不到主类”——这不是你代码写错了,是 JMH 本身不支持“直接运行 main 方法”的方式。它必须通过生成的 benchmark jar + 特定启动器执行,否则 classpath、annotation processor、fork 进程等全都不生效。
- 必须用 Maven 插件
jmh-maven-plugin构建可执行 benchmark jar,不能靠 IDEA 的绿色三角形运行 - IDEA 默认不会自动启用 annotation processing,
@Benchmark类不会被识别和生成桩代码 - 即使手动开启 annotation processor,也仅生成源码,不触发 fork 模式、预热、GC 控制等核心逻辑
怎么让 IDEA 正确识别并运行 JMH 测试
关键不是“配置 Java 环境”,而是让 IDEA 认出这是 JMH 工程,并把构建和运行流程交给 Maven 插件接管。
- 在
pom.xml中声明jmh-maven-plugin,并绑定到package生命周期(示例目标:生成benchmarks.jar) - 在 IDEA 的
Settings → Build → Compiler → Annotation Processors中勾选 “Enable annotation processing”,Processor path 填${m2_repo}/org/openjdk/jmh/jmh-generator-annprocess/1.37/jmh-generator-annprocess-1.37.jar(版本需匹配) - 写完
@Benchmark方法后,先执行mvn clean package,再运行生成的 jar:java -jar target/benchmarks.jar - 想在 IDEA 里点按钮运行?可以配一个 “Run Configuration”:Type 选 “Application”,Main class 填
org.openjdk.jmh.runner.ForkedMain,Program arguments 填-f 1 -wi 3 -i 5 YourBenchmarkClass,Working directory 指向项目根目录
常见错误现象和对应修复
这些不是环境没配好,而是 JMH 运行机制和 Java 工程惯例冲突导致的典型卡点。
-
Benchmark mode is mandatory:没加@Fork或@State,或参数里漏了-bm(如-bm avgt)。JMH 不接受无模式运行 -
WARNING: Unable to match any benchmarks:类名没按默认规则(*Benchmark.java),或方法没加@Benchmark,或 public 修饰符缺失 - 结果中
Score Error显示 N/A:单次 fork 时间太短(@Fork(jvmArgs = {"-Xmx2g"}) 或延长@Warmup(iterations = 5) - Mac 上报
Could not start forked VM:M1/M2 芯片下 JDK 架构不匹配,确保用 ARM64 JDK(非 Rosetta),且jmh-maven-plugin版本 ≥ 1.36
性能对比时容易忽略的陷阱
JMH 不是“测个耗时”,它是用严格控制的 JVM 行为来逼近真实性能边界。很多看似合理的写法,会让结果完全失真。
立即学习“Java免费学习笔记(深入)”;
- 别在
@Setup里做 I/O 或网络调用——它只执行一次,但会被算进整个 benchmark 生命周期 - 避免在
@Benchmark方法内 new 大对象,除非你明确要测 GC 压力;否则加@Fork(jvmArgsAppend = "-XX:+UseG1GC")并观察gc.count指标 - 两个方法对比时,确保它们处于同一
@State类中,否则 JIT 编译状态、分支预测历史、CPU cache line 对齐都不同 - 数值型结果看
avgt(平均耗时),别只盯score——后者可能是吞吐量(ops/s),单位反着来










