JMH (Java Microbenchmark Harness)
JMH 是 Java 的微基准测试工具,由 OpenJDK 团队开发,专门用于编写、运行和分析 Java 代码的微基准测试(microbenchmark)。
为什么需要 JMH
普通的基准测试方法(如多次循环调用方法并计时)存在很多问题:
-
JVM 的 JIT 编译优化(方法内联、死代码消除等)
-
预热效应(JVM 需要"热身"才能达到最佳性能)
-
垃圾回收的干扰
-
操作系统调度的影响
JMH 解决了这些问题,提供了准确的基准测试环境。
基本使用
1. 添加依赖
<dependency><groupId>org.openjdk.jmh</groupId><artifactId>jmh-core</artifactId><version>1.37</version>
</dependency>
<dependency><groupId>org.openjdk.jmh</groupId><artifactId>jmh-generator-annprocess</artifactId><version>1.37</version><scope>provided</scope>
</dependency>
2. 编写基准测试
import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;@BenchmarkMode(Mode.AverageTime) // 测试模式:平均时间
@OutputTimeUnit(TimeUnit.NANOSECONDS) // 输出时间单位
@State(Scope.Thread) // 每个测试线程一个实例
public class MyBenchmark {@Param({"10", "100", "1000"}) // 参数化测试private int length;private int[] array;@Setup // 初始化方法public void setup() {array = new int[length];// 初始化数组...}@Benchmark // 基准测试方法public int testMethod() {// 被测代码int sum = 0;for (int i : array) {sum += i;}return sum;}
}
3. 运行基准测试
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;public class BenchmarkRunner {public static void main(String[] args) throws RunnerException {Options opt = new OptionsBuilder().include(MyBenchmark.class.getSimpleName()).forks(1) // 使用1个进程.warmupIterations(5) // 预热5次.measurementIterations(5) // 正式测量5次.build();new Runner(opt).run();}
}
常用注解
注解 | 说明 |
---|---|
@Benchmark | 标记基准测试方法 |
@BenchmarkMode | 测试模式:Throughput(吞吐量)、AverageTime(平均时间)、SampleTime(采样时间)等 |
@OutputTimeUnit | 结果时间单位 |
@State | 定义测试状态的作用域 (Scope.Thread/Benchmark/Group) |
@Setup | 测试前的初始化方法 |
@TearDown | 测试后的清理方法 |
@Param | 参数化测试字段 |
@Fork | 指定fork次数(隔离测试) |
@Warmup | 预热配置 |
@Measurement | 正式测量配置 |
最佳实践
-
避免死代码消除:确保基准测试方法有返回值或副作用
-
合理设置预热:通常3-5次预热迭代
-
使用
@State
管理状态:避免在基准测试方法中初始化 -
多次测量:增加测量次数提高准确性
-
参数化测试:使用
@Param
测试不同输入规模 -
避免系统干扰:关闭其他程序,保持测试环境稳定
高级特性
-
Profiler支持:集成各种分析器(GC、堆栈等)
-
异步profiling:不影响基准测试运行
-
时间控制:精确控制测试时间
-
多线程测试:评估并发性能
典型输出示例
Benchmark (length) Mode Cnt Score Error Units
MyBenchmark.testMethod 10 avgt 5 15.234 ± 0.123 ns/op
MyBenchmark.testMethod 100 avgt 5 142.567 ± 1.234 ns/op
MyBenchmark.testMethod 1000 avgt 5 1356.789 ± 12.345 ns/op
JMH 是 Java 性能测试的事实标准工具,特别适合比较不同算法或实现的性能差异。