我们需要使用jmh进行微基准测试,因为传统方法易受jvm优化影响导致结果不准确。1. jmh通过预热、多次迭代等机制规避偏差;2. 提供注解如@benchmark、@setup精细控制测试;3. 使用blackhole防止死代码消除;4. 支持多jvm进程隔离测试干扰;5. 提供参数化测试、状态共享等高级功能;6. 结果包含平均时间、误差范围等指标便于分析。

JMH (Java Microbenchmark Harness) 的作用是帮助开发者编写可靠的微基准测试,从而精确测量Java代码的性能。它解决了传统基准测试中常见的偏差问题,比如JVM预热、代码优化等,为性能优化提供可信的数据支撑。

JMH 是进行精确 Java 性能测试的利器。

传统的性能测试方法,比如简单地循环执行代码片段并计算耗时,往往会受到JVM的各种优化措施的影响,导致结果不准确。例如,JIT编译器会根据代码的执行频率进行优化,使得后续的测试结果与首次执行的结果大相径庭。此外,垃圾回收、线程调度等因素也会对测试结果产生干扰。JMH通过一系列精巧的设计,比如预热、多次迭代、防止死代码消除等,有效地规避了这些问题,提供更可靠的性能数据。它就像一个专业的实验室,严格控制各种变量,确保测试结果的准确性。
立即学习“Java免费学习笔记(深入)”;
首先,你需要添加 JMH 的依赖到你的项目中(Maven 或 Gradle)。然后,创建一个类,并使用 JMH 提供的注解来标记你的测试方法。例如,@Benchmark 注解用于标记需要进行基准测试的方法,@State 注解用于定义测试状态,@Setup 和 @TearDown 注解用于在测试前后执行初始化和清理操作。一个简单的例子如下:

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
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;
import java.util.Random;
import java.util.concurrent.TimeUnit;
@State(Scope.Thread)
public class MyBenchmark {
private int[] data;
@Setup(Level.Trial)
public void setup() {
data = new Random().ints(1000).toArray();
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void testMethod(Blackhole blackhole) {
int sum = 0;
for (int value : data) {
sum += value;
}
blackhole.consume(sum); // 防止死代码消除
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(MyBenchmark.class.getSimpleName())
.forks(1)
.warmupIterations(5)
.measurementIterations(5)
.build();
new Runner(opt).run();
}
}这个例子展示了如何使用 @Benchmark 标记测试方法,使用 @Setup 进行初始化,并使用 Blackhole 防止死代码消除。main 方法用于配置和运行 JMH 测试。
JMH 提供了丰富的注解,用于控制基准测试的行为。一些常见的注解包括:
@Benchmark: 标记一个方法为基准测试方法。@State: 定义测试状态,可以指定状态的作用域(Thread, Group, Benchmark)。@Setup: 在基准测试方法执行之前执行,用于初始化测试数据。可以指定执行级别(Trial, Iteration, Invocation)。@TearDown: 在基准测试方法执行之后执行,用于清理测试数据。同样可以指定执行级别。@BenchmarkMode: 指定基准测试的模式,比如 AverageTime(平均执行时间)、Throughput(吞吐量)、SampleTime(采样时间)等。@OutputTimeUnit: 指定输出结果的时间单位。@Fork: 指定 JVM 进程的数量,用于隔离不同测试之间的影响。@Warmup: 指定预热迭代的次数,让 JVM 充分优化代码。@Measurement: 指定测量迭代的次数,用于收集性能数据。这些注解允许你精细地控制基准测试的各个方面,从而获得更准确和可靠的性能数据。
JMH 的测试结果通常包含多个指标,比如平均执行时间、吞吐量、误差范围等。解读这些结果需要一定的经验。首先,关注平均执行时间或吞吐量,这是衡量性能的主要指标。其次,关注误差范围(通常以 ± 符号表示),它表示测试结果的置信区间。如果两个测试结果的误差范围有重叠,则说明它们的性能差异可能不显著。此外,还需要注意测试结果的单位,比如纳秒、微秒、毫秒等。最后,结合具体的业务场景和性能需求,综合分析测试结果,才能得出有意义的结论。例如,如果一个方法的平均执行时间是 100 纳秒 ± 10 纳秒,而另一个方法的平均执行时间是 110 纳秒 ± 5 纳秒,那么可以认为这两个方法的性能差异不大。但如果第一个方法的平均执行时间是 100 纳秒 ± 1 纳秒,而第二个方法的平均执行时间是 110 纳秒 ± 1 纳秒,那么可以认为第二个方法的性能略差。
JMH 通过多种机制来防止常见的基准测试陷阱。
Blackhole 对象,强制使用测试结果,防止 JIT 编译器优化掉无用的代码。这些机制使得 JMH 能够提供更可靠和准确的性能数据,帮助开发者做出明智的性能优化决策。
JMH 提供了许多高级特性,可以满足更复杂的性能测试需求。
@Param 注解来定义测试参数,JMH 会自动为每个参数值运行一次测试。@State 注解来定义测试状态,并在多个测试方法之间共享状态。perfasm、jfr 等,来分析代码的性能瓶颈。这些高级特性使得 JMH 能够应对各种复杂的性能测试场景,帮助开发者深入了解代码的性能特征。
以上就是Java中JMH的作用 解析微基准测试的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号