JMH - Java 微基准测试工具(自助性能测试)@Benchmark

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

1、前言

在日常开发中,我们对一些代码的调用或者工具的使用会存在多种选择方式,在不确定他们性能的时候,我们首先想要做的就是去测量它。大多数时候,我们会简单的采用多次计数的方式来测量,来看这个方法的总耗时。

但是,如果熟悉JVM类加载机制的话,应该知道JVM默认的执行模式是JIT编译与解释混合执行。JVM通过热点代码统计分析,识别高频方法的调用、循环体、公共模块等,基于JIT动态编译技术,会将热点代码转换成机器码,直接交给CPU执行。

也就是说,JVM会不断的进行编译优化,这就使得很难确定重复多少次才能得到一个稳定的测试结果?所以,很多有经验的同学会在测试代码前写一段预热的逻辑。

JMH,全称 Java Microbenchmark Harness (微基准测试框架),是专门用于Java代码微基准测试的一套测试工具API,是由 OpenJDK/Oracle 官方发布的工具。何谓 Micro Benchmark 呢? 简单地说就是在 method 层面上的 benchmark,精度可以精确到微秒级

Java的基准测试需要注意的几个点:

  • 测试前需要预热。
  • 防止无用代码进入测试方法中。
  • 并发测试。
  • 测试结果呈现。

JMH的使用场景:

  1. 定量分析某个热点函数的优化效果
  2. 想定量地知道某个函数需要执行多长时间,以及执行时间和输入变量的相关性
  3. 对比一个函数的多种实现方式

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

文晓武

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值