1、前言
在日常开发中,我们对一些代码的调用或者工具的使用会存在多种选择方式,在不确定他们性能的时候,我们首先想要做的就是去测量它。大多数时候,我们会简单的采用多次计数的方式来测量,来看这个方法的总耗时。
但是,如果熟悉JVM类加载机制的话,应该知道JVM默认的执行模式是JIT编译与解释混合执行。JVM通过热点代码统计分析,识别高频方法的调用、循环体、公共模块等,基于JIT动态编译技术,会将热点代码转换成机器码,直接交给CPU执行。

也就是说,JVM会不断的进行编译优化,这就使得很难确定重复多少次才能得到一个稳定的测试结果?所以,很多有经验的同学会在测试代码前写一段预热的逻辑。
JMH,全称 Java Microbenchmark Harness (微基准测试框架),是专门用于Java代码微基准测试的一套测试工具API,是由 OpenJDK/Oracle 官方发布的工具。何谓 Micro Benchmark 呢? 简单地说就是在 method 层面上的 benchmark,精度可以精确到微秒级。
Java的基准测试需要注意的几个点:
- 测试前需要预热。
- 防止无用代码进入测试方法中。
- 并发测试。
- 测试结果呈现。
JMH的使用场景:
- 定量分析某个热点函数的优化效果
- 想定量地知道某个函数需要执行多长时间,以及执行时间和输入变量的相关性
- 对比一个函数的多种实现方式
2、开始前的步骤
项目使用的是 Maven,因此只要对 pom.xml 添加依赖即可。
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.19</version>
<scope>provided</scope>
</dependency>
3、例子
记得之前和宿友讨论 ArrayList 和 LinkedList 的遍历的性能差别,当时以一种不太妥当的方法进行测试,导致无法得到比较好的结果,刚好这里可以使用这两个来进行比较。
4、代码
4.1 创建业务服务类
package com.wenxiaowu.jmh;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* 业务服务类
*/
public class BizService {
private int n = 10000;
private List<Integer> arrayList;
private List<Integer> linkedList;
public BizService () {
arrayList = new ArrayList<>(0);
linkedList = new LinkedList<>();
for (int i = 0; i < n; i++) {
arrayList.add(i);
linkedList.add(i);
}
}
/**
* 扫描array集合,待测试的方法1
*/
public void scanArray() {
for (int i = 0; i < n; i++) {
this.arrayList.get(i);
}
}
/**
* 扫描list集合,待测试的方法2
*/
public void scanList() {
for (int i = 0; i < n; i++) {
this.linkedList.get(i);
}
}
/**
* 清空数据
*/
public void clear() {
for (int i = 0; i < n; i++) {
this.arrayList.remove(0);
this.linkedList.remove(0);
}
}
}
4.2 创建性能测试代码
package com.wenxiaowu.jmh;
import org.openjdk.jmh.annotations.*;
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.concurrent.TimeUnit;
@BenchmarkMode(Mode.Throughput) // 吞吐量
@OutputTimeUnit(TimeUnit.MILLISECONDS) // 结果所使用的时间单位
@State(Scope.Thread) // 每个测试线程分配一个实例
@Fork(2) // Fork进行的数目
@Warmup(iterations = 1) // 先预热1轮
@Measurement(iterations = 2) // 进行2轮测试
public class JmhMainApplication {
BizService bizService;
@Setup(Level.Trial) // 初始化方法,在全部Benchmark运行之前进行
public void init() {
bizService = new BizService();
}
@Benchmark
public void arrayTraverse() {
bizService.scanArray();
}
@Benchmark
public void listTraverse() {
bizService.scanList();
}
@TearDown(Level.Trial) // 结束方法,在全部Benchmark运行之后进行
public void arrayRemove() {
bizService.clear();
}
public static void main(String[] args) throws RunnerException {
Options o

本文介绍了如何使用Java Microbenchmark Harness (JMH)进行性能测试,特别是在比较ArrayList和LinkedList遍历性能上的应用。通过预热、设置测试参数,JMH确保了测试结果的准确性。结果显示,ArrayList的遍历性能显著优于LinkedList。
最低0.47元/天 解锁文章
2762

被折叠的 条评论
为什么被折叠?



