JMH是Java Micro Benchmark Harness的简写,是专门用于代码微基准测试的工具集
用JMH进行微基准测试
引入依赖
## 简单测试ArrayList和LinkedList
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Thread)
public class JMHExample01 {
private final static String DATA = "DUMMY DATA";
private List<String> arrayList;
private List<String> linkedList;
@Setup(Level.Iteration)
public void setUp() {
this.arrayList = new ArrayList<>();
this.linkedList = new LinkedList<>();
}
@Benchmark
public List<String> arrayListAdd() {
this.arrayList.add(DATA);
return arrayList;
}
@Benchmark
public List<String> linkedListAdd() {
this.linkedList.add(DATA);
return this.linkedList;
}
public static void main(String[] args) throws RunnerException {
final Options opts = new OptionsBuilder().include(JMHExample01.class.getSimpleName())
.forks(1)
.measurementIterations(10)
.warmupIterations(10)
.build();
new Runner(opts).run();
}
}
@Benchmark标记基准测试方法: 类似于@Test,JMH对基准测试的方法需要使用@Benchmark注解进行标记,否则方法将被视为普通方法
Warmup以及Measurement: 主要是分批次地执行基准测试方法
Warmup 所做的就是在基准测试代码正式度量之前,先对其进行预热,使得代码的执行是经历过了类的早期优化、JVM运行期编译、JIT优化之后的最终状态,从而能够获得代码真实的性能数据
Measurement 则是真正的度量操作,在每一轮的度量中,所有的度量数据会被纳入统计之中
使用注解进行预热
@Measurement(iterations = 5)
@Warmup(iterations = 2)
@BenchmarkMode: 声明使用哪一种模式来运行
1.AverageTime
输出结果
2.Throughput 方法吞吐量
3.SampleTime 时间采样)的方式是指采用一种抽样的方式来统计基准测试方法的性能结果
4. SingleShotTime 主要可用来进行冷测试
5.多Mode以及All
@OutputTimeUnit 提供了统计结果输出时的单位
最终统计结果
- @Thread 设置线程的数量
- @State(Scope.Benchmark) 多个线程共用一个实例
- @Fork: 虽然Java支持多线程,但是不支持多进程,这就导致了所有的代码都在一个进程中运行,相同的代码在不同时刻的执行可能会引入前一阶段对进程profiler的优化,甚至会混入其他代码profiler优化时的参数,这很有可能会导致我们所编写的微基准测试出现不准确的问题
- Setup以及TearDown: JMH提供了两个注解@Setup和@TearDown用于套件测试
其中@Setup会在每一个基准测试方法执行前被调用,通常用于资源的初始化,@TearDown则会在基准测试方法被执行之后被调用,通常可用于资源的回收清理工作