0Pricing
Java Academy · 课时

编写基准测试

@Benchmark 与模式

编写基准测试 是 CoddyKit 上的免费 Java Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。

编写基准测试

JMH 基准测试就是普通类中一个带有 @Benchmark 注解的方法。JMH 的注解处理器会围绕它生成测试框架。本课将介绍用于定义测量内容和测量方式的注解。

@Benchmark 注解

为任意公共方法添加 @Benchmark,JMH 就会反复调用它,并为每次调用计时。方法的返回值应该被返回(而不是丢弃),这样 JMH 才能消费它。

最小基准测试类

下面是基准测试的基本结构。导入内容是 org.openjdk.jmh.annotations.*。由于 JMH 不在此运行器的类路径中,下面的内容仅用于说明。

import org.openjdk.jmh.annotations.Benchmark;

public class StringBench {
    @Benchmark
    public String concat() {
        return "foo" + System.nanoTime();
    }
}

基准测试模式

@BenchmarkMode 决定报告的内容:

  • 吞吐量 — 单位时间内的操作数(越高越好)。
  • AverageTime — 每次操作所需的时间(越低越好)。
  • SampleTime — 时间分布(百分位数)。
  • SingleShotTime — 执行一次调用,适合冷启动。
import org.openjdk.jmh.annotations.*;

public class Bench {
    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    public int work() {
        return 2 + 2;
    }
}

选择输出单位

@OutputTimeUnit 设置报告所使用的时间单位,使数值更易读。对于快速操作,使用纳秒很合适;对于较慢的操作,则可以使用毫秒。

import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.*;

public class Bench {
    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public int work() {
        return 42;
    }
}

返回结果

始终返回工作结果。JMH 会自动将返回的值传递给黑洞,从而防止死代码消除。计算结果却将其丢弃的 void 基准测试是一个典型错误。

注解默认设置

注解可以放在方法上,也可以放在整个类上。类级别的注解会应用于该类中的每个 @Benchmark,当您有多个相关基准测试时,这可以避免重复配置。

分叉运行

@Fork(n) 会在 n 个全新的 JVM 进程中运行基准测试。分叉运行会将每次运行与之前基准测试积累的即时编译器配置隔离开来,从而提高可复现性。默认值为一次分叉运行。

import org.openjdk.jmh.annotations.*;

@Fork(2)
public class Bench {
    @Benchmark
    public long now() {
        return System.nanoTime();
    }
}

启动运行器

您可以通过配置 Options 对象和 Runner 的 main 来启动基准测试,也可以通过生成的可执行 JAR 启动。include(...) 正则表达式用于选择要运行的基准测试。

import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.*;

public class Launcher {
    public static void main(String[] args) throws Exception {
        Options opt = new OptionsBuilder()
            .include("Bench")
            .build();
        new Runner(opt).run();
    }
}

读取输出

JMH 会打印一张表,其中包含基准测试名称、模式、样本数量、分数、分数误差和单位,例如:Bench.work avgt 25 3.142 +/- 0.011 ns/op。+/- 表示置信区间。

保持基准测试专注

每个基准测试都应该只测量一件事。将设置、输入/输出和被测试的操作混在一起会使结果变得模糊。请将准备工作移到 @Setup 方法中(状态部分会介绍),这样只有热点路径会被计时。

快速检查

检验您对编写基准测试的理解。

回顾

您学会了如何编写 JMH 基准测试:

  • 为方法添加 @Benchmark 注解并返回结果。
  • @BenchmarkMode 可选择吞吐量、AverageTime、SampleTime 或 SingleShotTime。
  • @OutputTimeUnit 设置易读的单位;@Fork 会在全新的 JVM 中隔离每次运行。
  • 使用运行器 + 选项或生成的 JAR 启动。
  • 让每个基准测试都专注于单个热点路径。

常见问题解答

「编写基准测试」课时是免费的吗?

是的 — 「编写基准测试」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。

「编写基准测试」这节课中我会学到什么?

@Benchmark 与模式 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Java Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「编写基准测试」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Java Academy 课中编写并运行代码吗?

能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 为什么使用 JMH
  2. 编写基准测试
  3. 预热与迭代
  4. 避免死代码消除
← 返回 Java Academy