✨JMH(Java Microbenchmark Harness)✨

JMH(Java Microbenchmark Harness)是一个专门用于编写、运行和分析Java微基准测试的工具。它由OpenJDK团队开发,旨在提供精确的基准测试结果,避免常见的基准测试陷阱,如JVM的优化、即时编译(JIT)等影响。

核心知识点

  1. 基准测试的目的

    • 基准测试用于测量代码的性能,通常是在微秒或纳秒级别。
    • 它可以帮助开发者识别性能瓶颈,优化代码。
  2. JMH的特点

    • 精确性:JMH通过多次迭代和预热来减少JVM优化对测试结果的影响。
    • 可配置性:可以配置测试的模式(如吞吐量、平均时间、采样时间等)。
    • 易于使用:通过注解和简单的API,开发者可以轻松编写基准测试。
  3. 关键注解

    • @Benchmark:标记一个方法为基准测试方法。
    • @State:标记一个类为状态类,用于存储测试中的状态。
    • @Setup@TearDown:分别在基准测试开始前和结束后执行的方法。
    • @Warmup:配置预热迭代次数和时间。
    • @Measurement:配置实际测试的迭代次数和时间。
    • @Fork:配置JVM实例的fork次数。
  4. 测试模式

    • Throughput(吞吐量) :测量单位时间内执行的操作次数。
    • AverageTime(平均时间) :测量每次操作的平均时间。
    • SampleTime(采样时间) :测量每次操作的时间分布。
    • SingleShotTime(单次时间) :测量单次操作的时间。

示例代码 ‍ DEMO

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

@State(Scope.Thread) // 每个线程都有自己的状态实例
@BenchmarkMode(Mode.AverageTime) // 测试模式为平均时间
@OutputTimeUnit(TimeUnit.NANOSECONDS) // 输出时间单位为纳秒
@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) // 预热3次,每次1秒
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) // 测试5次,每次1秒
@Fork(1) // 使用1个JVM实例
public class StringConcatBenchmark {

    private String str1;
    private String str2;

    @Setup // 在基准测试开始前执行
    public void setup() {
        str1 = "Hello";
        str2 = "World";
    }

    @Benchmark // 标记为基准测试方法
    public String concatWithPlus() {
        return str1 + " " + str2; // 使用 + 进行字符串拼接
    }

    @Benchmark // 另一个基准测试方法
    public String concatWithStringBuilder() {
        return new StringBuilder().append(str1).append(" ").append(str2).toString(); // 使用 StringBuilder
    }

    @TearDown // 在基准测试结束后执行
    public void tearDown() {
        // 这里可以清理资源
    }
}

运行JMH测试 ‍♂️

  1. 添加依赖
    如果你使用 Maven,需要在 pom.xml 中添加 JMH 依赖:

    
        org.openjdk.jmh
        jmh-core
        1.36
    
    
        org.openjdk.jmh
        jmh-generator-annprocess
        1.36
        provided
    
    
  2. 编译项目 ⚙️
    运行以下命令编译项目并生成 JMH 基准测试的 JAR 文件:

    mvn clean install
    
  3. 运行基准测试
    运行生成的 JAR 文件来执行基准测试:

    java -jar target/benchmarks.jar
    

输出结果示例

运行后,你会看到类似以下的输出:

Benchmark                                Mode  Cnt   Score   Error  Units
StringConcatBenchmark.concatWithPlus     avgt    5  23.456 ± 1.234  ns/op
StringConcatBenchmark.concatWithStringBuilder  avgt    5  15.678 ± 0.987  ns/op
  • Score:每次操作的平均时间(单位:纳秒)。
  • Error:误差范围。
  • Units:时间单位。

代码解析

  1. @State(Scope.Thread)
    表示每个线程都会有一个独立的实例,避免线程竞争问题。

  2. @BenchmarkMode(Mode.AverageTime)
    测试模式为平均时间,还可以选择 Throughput(吞吐量)、SampleTime(采样时间)等。

  3. @Warmup@Measurement

    • @Warmup:预热阶段,让 JVM 充分优化代码。
    • @Measurement:实际测试阶段。
  4. @Fork
    指定运行的 JVM 实例数量,避免 JVM 优化对测试结果的影响。

  5. @Benchmark
    标记基准测试方法,方法内的代码会被 JMH 测量。

总结

JMH是一个非常强大的工具,能够帮助开发者精确测量Java代码的性能。通过合理的配置和使用,可以避免常见的基准测试陷阱,得到可靠的测试结果。️

你可能感兴趣的:(java,开发语言)