JMH简介
JMH即Java Microbenchmark Harness,是Java用来做基准测试的一个工具,该工具由OpenJDK提供并维护,测试结果可信度高。
基准测试Benchmark是测量、评估软件性能指标的一种测试,对某个特定目标场景的某项性能指标进行定量的和可对比的测试。
1. 创建maven 项目,添加依赖
<!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-core --> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-core</artifactId> <version>1.21</version> </dependency> <!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-generator-annprocess --> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-generator-annprocess</artifactId> <version>1.21</version> <scope>test</scope> </dependency>
2.idea安装JMH插件 JMH plugin v1.0.3
3.由于用到了注解,打开运行程序注解配置
compiler -> Annotation Processors -> Enable Annotation Processing
4.定义需要测试类
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class PS {
static List<Integer> nums = new ArrayList<>();
static {
Random r = new Random();
for (int i = 0; i < 10000; i++) nums.add(1000000 + r.nextInt(1000000));
}
static void foreach() {
nums.forEach(v->isPrime(v));
}
static void parallel() {
nums.parallelStream().forEach(PS::isPrime);
}
static boolean isPrime(int num) {
for(int i=2; i<=num/2; i++) {
if(num % i == 0) return false;
}
return true;
}
}
5.写单元测试
import org.openjdk.jmh.annotations.Benchmark;
import static org.junit.jupiter.api.Assertions.*;
public class PSTest {
@BenchmarkMode(Mode.AverageTime) // 指定mode为Mode.AverageTime
@Benchmark
@Fork(1)
@Threads(2)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) //测试5次,每次测1秒钟
public void testForEach() {
PS.foreach();
}
}
6.运行测试类,如果遇到下面的错误:
ERROR: org.openjdk.jmh.runner.RunnerException: ERROR: Exception while trying to acquire the JMH lock (C:\WINDOWS\/jmh.lock): C:\WINDOWS\jmh.lock (拒绝访问。), exiting. Use -Djmh.ignoreLock=true to forcefully continue. at org.openjdk.jmh.runner.Runner.run(Runner.java:216) at org.openjdk.jmh.Main.main(Main.java:71)
这个错误是因为JMH运行需要访问系统的TMP目录,解决办法是:
打开RunConfiguration -> Environment Variables -> include system environment viables
7.阅读测试报告
JMH中的基本概念
-
Warmup 预热,由于JVM中对于特定代码会存在优化(本地化),预热对于测试结果很重要
-
@Measurement 总共执行多少次测试
iterations
:测量次数;time与timeUnit
:每次测量的持续时间,timeUnit
指定时间单位,本例中:每次测量持续1秒,1秒内执行的testForEach
方法的次数是不固定的,由方法执行耗时和time决定。 -
@OutputTimeUnit 用于指定输出的方法执行耗时的单位
-
@Fork 用于指定
fork
出多少个子进程来执行同一基准测试方法。假设我们不需要多个进程,那么 可以使用@Fork
指定为进程数为1 -
@Threads 用于指定使用多少个线程来执行基准测试方法,如果使用
@Threads
指定线程数为2
,那么每次测量都会创建两个线程来执行基准测试方法。 -
@BenchmarkMode 基准测试的模式
通过
JMH
我们可以轻松的测试出某个接口的吞吐量、平均执行时间等指标的数据。假设我想测试的方法的平均耗时,那么可以使用
@BenchmarkMode
注解指定测试维度为Mode.AverageTime
。 -
@Benchmark 测试哪一段代码
-
@Warmup
预热,有三个配置项:iterations
:预热次数;time与timeUnit
:每次预热的持续时间,timeUnit
指定时间单位。
官方样例: code-tools/jmh: 2be2df7dbaf8 /jmh-samples/src/main/java/org/openjdk/jmh/samples/
参考文章: https://blog.csdn.net/ZYC88888/article/details/113741316