bigywater.tech
Java · 307

JMH 基准测试误区

基准测试最容易测出「没有发生的计算」。这篇用 JMH 逐个触发:死代码消除、常量折叠、基准里的循环、逃逸分析,再看手写计时为什么不可靠。

0.314 vs 0.591 ns
sqrt 丢弃结果与返回结果的 JMH 结果(空方法是 0.332 ns)
0.314 → 2.398 ns
分配 int[16] 丢弃与返回的耗时(丢弃时对象没有分配)
10500 → 8.89 ns
手写计时 parseInt 从第 1 批到稳定后的每次耗时(JMH 是 4.953 ns)

JMH 基准

实测 · 本机执行输出
  # JMH version: 1.37
  # VM version: JDK 21.0.12.1, OpenJDK 64-Bit Server VM, 21.0.12.1
  # Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
  # Warmup: 2 iterations, 1 s each
  # Measurement: 3 iterations, 1 s each
  # Threads: 1 thread, will synchronize iterations
  # JMH version: 1.37
  a1_sqrtDiscarded            0.314 ± 0.003 ns/op
  a2_sqrtReturned             0.591 ± 0.003 ns/op
  b1_sqrtConstant             0.313 ± 0.001 ns/op
  b2_sqrtStaticFinal          0.313 ± 0.001 ns/op
  b3_sqrtStateField           0.591 ± 0.002 ns/op
  c1_oneElement               0.628 ± 0.003 ns/op
  c2_loopOf1000             323.024 ± 4.85 ns/op
  e1_allocDiscarded           0.314 ± 0.002 ns/op
  e2_allocReturned            2.398 ± 0.028 ns/op
  e3_allocStoredToField       2.765 ± 0.034 ns/op
  p_parseInt                  4.953 ± 0.019 ns/op
  z0_empty                    0.332 ± 0.125 ns/op

手写计时

实测 · 本机执行输出
  第  1 批        1 次:  10500.00 ns/次
  第  2 批       10 次:    929.20 ns/次
  第  3 批      100 次:    890.42 ns/次
  第  4 批     1000 次:    402.33 ns/次
  第  5 批    10000 次:    126.92 ns/次
  第  6 批   100000 次:     27.58 ns/次
  第  7 批  1000000 次:     10.64 ns/次
  第  8 批 10000000 次:      8.90 ns/次
  第  9 批 10000000 次:      8.89 ns/次
  第 10 批 10000000 次:      8.89 ns/次
  (对照:第一部分里同一个操作的 JMH 基准 p_parseInt = 4.953 ns/op)
  同一个程序 -Xint(只解释执行)的最后一批:   第 10 批 10000000 次:   1200.11 ns/次

分步演示

JMH 基准陷阱
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,JMH 1.37,编译器 Blackhole(JMH 自动检测),Apple Silicon;2 个 fork、2 次预热 + 3 次测量,每次 1 秒
    • 没有验证:JMH 手写计时数字差异的原因、JDK 27 上同样基准的结果、多线程基准与共享状态、-prof 分析器(perfasm / gc)输出、x86 上的结果
    京ICP备2026067502号-1京公网安备11010502063487号