JMH 基准测试 示例

625 阅读2分钟

在看Spring源码时, 可以看到有些子项目之下, 有jmh模块, 这个模块是用来做什么的呢?

image.png

JMH(Java Microbenchmark Harness), openjdk提供的测试框架, 可以用来做微基准测试.

关于基准测试, 可以查看百度百科. 百度百科-基准测试

那么, 一个Java项目怎么做JMH? 先运行一个简单的demo

技术栈:

  • JDK版本 JDK8

  • 构建工具 gradle

  • jmh版本 1.33

build.gradle

当前示例使用的是Main方法测试的, 如果是单元测试, 导入依赖时, 要使用testImplementation而不是implementation

dependencies {
    //......
    // jmh
    implementation('org.openjdk.jmh:jmh-core:1.33')
    annotationProcessor("org.openjdk.jmh:jmh-generator-annprocess:1.33")
    //......
}

ArrayJmh.java

测试Java数组和ArrayList循环赋值性能

// 基准测试模式
@BenchmarkMode({Mode.SampleTime, Mode.AverageTime})
// 预热参数 > 预热迭代次数;每次预热迭代的时间;预热迭代持续时间的时间单位;每个操作的基准方法调用次数
@Warmup(iterations = 0, time = 500, timeUnit = TimeUnit.MILLISECONDS, batchSize = 1)
// 测量参数 > 测量迭代次数;每次测量迭代的时间;测量迭代持续时间的时间单位;每个操作的基准方法调用次数
@Measurement(iterations = 1, time = 500, timeUnit = TimeUnit.MILLISECONDS, batchSize = 1)
// 运行的线程数
@Threads(1)
// 分叉参数 > 分叉的次数;
@Fork(0)
// 标记状态对象: 基准状态范围
@State(Scope.Benchmark)
// 事件单位
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public class ArrayJhm {

    @Param({"10"})
    private int len;
    @Param({"10"})
    private int size;

    @Benchmark
    public void arrayMark(Blackhole blackhole){
        Integer[] array = new Integer[len];
        for (int i=0; i < len; i++) {
            array[i] = i;
        }
        blackhole.consume(array);
    }

    @Benchmark
    public void listList(Blackhole blackhole){
        List<Integer> list = new ArrayList<>();
        for (int i=0; i < size; i++) {
            list.add(i);
        }
        blackhole.consume(list);
    }

    public static void main(String[] args) throws RunnerException {
        Options options = new OptionsBuilder()
                .include(ArrayJhm.class.getSimpleName())
                .result("mark/mark."+ DateUtil.formatDateTime(new Date()) +".json")
                .resultFormat(ResultFormatType.JSON)
                .build();

        new Runner(options).run();
    }

}

执行main方法, 可以打印出具体的性能数据

image.png

image.png

可以看出, 在此情况下, 数组的性能要高于arrayList

image.png

也可以在代码中指定到处数据, 将导出的数据导入到网上的工具网站, 可以更直观的观看性能数据

例如: jmh-visual-chart

image.png

当前示例只是为了跑通环境, 后续继续探索JMH的神奇功能


PS, 如果出现下述错误

Exception in thread "main" java.lang.RuntimeException: ERROR: Unable to find the resource: /META-INF/BenchmarkList
   at org.openjdk.jmh.runner.AbstractResourceReader.getReaders(AbstractResourceReader.java:98)
   at org.openjdk.jmh.runner.BenchmarkList.find(BenchmarkList.java:124)
   at org.openjdk.jmh.runner.Runner.internalRun(Runner.java:253)
   at org.openjdk.jmh.runner.Runner.run(Runner.java:209)
   at jin.panpan.jmh.ArrayJhm.main(ArrayJhm.java:67)

是因为执行过程中没有加载到 jmh-generator-annprocess 导致的, 需要根据代码, 按生命周期导入包.