JMH微基准测试框架学习笔记

一、简介

JMH(Java Microbenchmark Harness)是一个用于编写、构建和运行Java微基准测试的框架。它提供了丰富的注解和工具,用于精确控制测试的执行和结果测量,从而帮助我们深入了解代码的性能特性。

二、案例实战

  1. 在你的pom文件中导入如下依赖:
        <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-core</artifactId>
            <version>1.21</version>
        </dependency>

        <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-generator-annprocess</artifactId>
            <version>1.21</version>
        </dependency>

要使用JMH进行微基准测试,你需要在项目的构建系统(如Maven或Gradle)中引入JMH的依赖。

  1. 便携示例代码

下面是一个简单的JMH测试示例,用于比较直接访问数组元素和通过方法访问数组元素的性能差异。

package cn.pottercoding.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;

/**
 * @author Mr.Sun
 * @since 2024年03月20日
 *
 * 一个简单的JMH测试示例,用于比较直接访问数组元素和通过方法访问数组元素的性能差异。
 */
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class ArrayAccessBenchmark {

    // 数组大小
    private static final int ARRAY_SIZE = 10000;

    // 初始化数组
    private int[] array = new int[ARRAY_SIZE];

    // 初始化方法,用于填充数组
    @Setup
    public void setup() {
        for (int i = 0; i < ARRAY_SIZE; i++) {
            array[i] = i;
        }
    }

    // 直接访问数组元素
    @Benchmark
    public int directAccess() {
        int sum = 0;
        for (int i = 0; i < ARRAY_SIZE; i++) {
            sum += array[i];
        }
        return sum;
    }

    // 通过方法访问数组元素
    @Benchmark
    public int methodAccess() {
        int sum = 0;
        for (int i = 0; i < ARRAY_SIZE; i++) {
            sum += getElement(i);
        }
        return sum;
    }

    // 获取数组元素的方法
    private int getElement(int index) {
        return array[index];
    }

    // 主方法,用于运行基准测试
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(ArrayAccessBenchmark.class.getSimpleName())
                .build();

        new Runner(opt).run();
    }
}

接下来让我们一起看下上面示例代码中用到的每个JMH注解的含义:

  1. @BenchmarkMode
    这个注解用于指定基准测试的模式。Mode.AverageTime表示测量的是每次操作的平均执行时间。JMH提供了多种模式,如Throughput(吞吐量,即每秒完成的操作数)和SampleTime(采样时间)等。

  2. @Warmup@Measurement
    @Warmup:用于指定预热阶段的相关设置。预热阶段用于让JVM的JIT编译器有时间优化测试代码,并使得缓存、垃圾回收等达到稳定状态。iterations指定预热迭代的次数,time和timeUnit分别指定预热阶段的总时间和时间单位。
    @Measurement:用于指定实际测量阶段的相关设置。这些设置类似于预热阶段,但它们是用于收集基准测试结果的。

  3. @State
    这个注解用于定义测试状态。Scope.Thread表示每个测试线程都有自己的测试状态实例。这样可以避免多线程之间的状态共享问题。其他可能的范围还包括Scope.Benchmark(所有线程共享同一个状态实例)和Scope.Group(每个测试组共享一个状态实例)。

  4. @OutputTimeUnit
    这个注解用于指定输出结果的时间单位。在这个例子中,TimeUnit.NANOSECONDS表示输出的时间将以纳秒为单位。

  5. @Setup
    这个注解用于标记在每次基准测试方法运行之前应该执行的方法。它通常用于初始化测试所需的数据或状态。在这个例子中,setup()方法用于填充数组。

  6. @Benchmark
    这个注解用于标记一个基准测试方法。JMH会运行这个方法多次,并收集相关的性能数据。在这个例子中,directAccess()methodAccess()都是基准测试方法,它们分别测试直接访问数组元素和通过方法访问数组元素的性能。

  7. @Param
    虽然这个注解在上面的示例代码中并没有使用,但它是一个常见的JMH注解,用于参数化基准测试。通过在测试类中的字段上使用@Param注解,并指定不同的值,你可以为同一个基准测试方法创建多个不同的测试场景。

执行结果如下:
在这里插入图片描述

代码执行结果分析:

  1. directAccess() 方法
    这个方法直接通过数组索引访问数组元素,并计算它们的和。由于它直接操作数组的内存位置,因此通常是最快的访问方式。在大多数情况下,directAccess() 方法应该会获得较低的平均执行时间。

  2. methodAccess() 方法
    这个方法通过调用 getElement() 方法来访问数组元素。虽然getElement()方法内部也是直接访问数组,但是方法调用的开销(如参数传递、栈帧创建等)通常会比直接访问要高一些。因此,methodAccess() 方法的平均执行时间很可能会比 directAccess() 方法稍长。

  3. 结果比较
    JMH会运行每个基准测试方法多次,并收集每次运行的执行时间。然后,它会计算这些时间的平均值、标准差等统计信息,并将它们输出到控制台或文件中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/472793.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024最新自动化测试面试题合集 (附答案)

1、你会封装自动化测试框架吗&#xff1f; 这个问得最多&#xff0c;甚至有很多公司直接写在招聘要求中&#xff01; 当然可以&#xff0c;自动化框架主要的核心框架就是分层PO模式&#xff1a;分别为&#xff1a;基础封装层BasePage&#xff0c;PO页面对象层&#xff0c;Tes…

Linux系统

yum 命令 安装软件 1.安装yum包&#xff1a; $ yum install PACKAGE_NAME Bash 2.yum包装&#xff1a; $ yum remove PACKAGE_NAME Shell 3.重新安装一个yum包&#xff1a; $ yum reinstall PACKAGE_NAME Bash 4.搜索yum包&#xff1a; $ yum search PACKAGE_NAME …

媒体发稿途径,怎么样去网络媒体投稿,媒体发布一般价格多少钱?

在信息爆炸的时代&#xff0c;媒体作为传递信息的重要渠道&#xff0c;成为企业推广的重要手段。然而&#xff0c;如何去网络媒体投稿&#xff0c;以及媒体发布的价格却是困扰很多企业和个人的问题。今天&#xff0c;我们将会为大家介绍一种简单易行的方式&#xff1a;媒介多多…

蓝桥杯练习05水果摆盘

水果摆盘 介绍 目前CSS3中新增的Flex弹性布局已经成为前端页面布局的首选方式&#xff0c;这次试题将利用Flex实现经典布局效果。 准备 开始答题前&#xff0c;需要先打开本题的项目代码文件夹&#xff0c;目录结构如下&#xff1a; 其中&#xff1a; index.css是本次需要补…

Visual Studio 2013 - 重置窗口布局

Visual Studio 2013 - 重置窗口布局 1. Microsoft Visual Studio 2013 - 重置窗口布局References 1. Microsoft Visual Studio 2013 - 重置窗口布局 窗口 -> 重置窗口布局 References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

闭包机制的底层实现原理

说明:此次分享不涉及ES6的let,const,块级作用域,这些其实都是对本次分享内容的扩展。 闭包的重要性 JS的内功心法,闭包是JavaScript中非常重要的核心概念,关系着JS里很多核心的机制,理解了它,很多问题都会迎刃而解,不理解闭包用JS永远像隔着一层窗户纸。 前端发展日新…

2 使用GPU理解并行计算

2.1 简介 本章旨在对并行程序设计的基本概念及其与GPU技术的联系做一个宽泛的介绍。本章主要面向具有串行程序设计经验&#xff0c;但对并行处理概念缺乏了解的读者。我们将用GPU的基本知识来讲解并行程序设计的基本概念。 2.2 传统的串行代码 绝大多数程序员是在串行程序占据…

备战蓝桥杯D33 - 真题 - 松散子序列

题目描述 解题思路 ps&#xff1a;思路是我看了大佬的题解后自己的理解&#xff0c;自己给自己捋清楚思路。 1.设置输入&#xff0c;将字符串输入 2.因为输入的是字符&#xff0c;但要找出字符的最大价值&#xff0c;所以先将字符串转化成对应的数值。 这时候就要用到ord函…

中国(京津冀)太阳能光伏展

中国(京津冀)太阳能光伏展是一场关于太阳能光伏技术和产业的展览会&#xff0c;主要在中国的京津冀地区举办。该展览会旨在推动太阳能光伏产业的发展&#xff0c;促进技术交流和商业合作。 在中国&#xff0c;太阳能光伏产业一直是重点发展的领域之一。中国政府制定了一系列政策…

水电能源智能化监控系统

水电能源智能化监控系统是利用现代信息技术&#xff0c;对水电站的运行状态、设备性能、环境参数等进行实时监测和管理的一种智能化系统。随着我国水电能源事业的快速发展&#xff0c;水电能源智能化监控系统在水电能源行业中的应用越来越广泛&#xff0c;为我国水电能源事业的…

【Qt学习笔记】(六)界面优化

界面优化 1 QSS1.1 背景介绍1.2 基本语法1.3 QSS设置方式1.3.1 指定控件样式设计1.3.2 全局样式设置1.3.3 使用 Qt Designer 编辑样式 1.4 选择器1.4.1选择器概况1.4.2 子控件选择器&#xff08;Sub-Controls&#xff09;1.4.3伪类选择器(Pseudo-States) 1.5 样式属性1.5.1 盒模…

[C++]20:unorderedset和unorderedmap结构和封装。

unorderedset和unorderedmap结构和封装 一.哈希表&#xff1a;1.直接定址法&#xff1a;2.闭散列的开放定址法&#xff1a;1.基本结构&#xff1a;2.insert3.find4.erase5.补充&#xff1a;6.pair<k,v> k的数据类型&#xff1a; 3.开散列的拉链法/哈希桶&#xff1a;1.基…

PyTorch 深度学习(GPT 重译)(四)

第二部分&#xff1a;从现实世界的图像中学习&#xff1a;肺癌的早期检测 第 2 部分的结构与第 1 部分不同&#xff1b;它几乎是一本书中的一本书。我们将以几章的篇幅深入探讨一个单一用例&#xff0c;从第 1 部分学到的基本构建模块开始&#xff0c;构建一个比我们迄今为止看…

图书馆RFID(射频识别)数据模型压缩/解压缩算法实现小工具

1. 前言 最近闲来无聊&#xff0c;看了一下《图书馆射频识别数据模型第1部分&#xff1a;数据元素的设置及应用规则》以及《图书馆射频识别数据模型第2部分&#xff1a;基于ISO/IEC 15962的数据元素编码方案》&#xff0c;决定根据上面的编码方法实现一下该算法&#xff0c;于…

算法沉淀——贪心算法四(leetcode真题剖析)

算法沉淀——贪心算法四 01.最长回文串02.增减字符串匹配03.分发饼干04.最优除法 01.最长回文串 题目链接&#xff1a;https://leetcode.cn/problems/longest-palindrome/ 给定一个包含大写字母和小写字母的字符串 s &#xff0c;返回 通过这些字母构造成的 最长的回文串 。 …

【软件测试】如何设计自动化测试脚本

企业中如何设计自动化测试脚本呢&#xff1f;今天我们就来为大家分享一些干货。 一、线性设计 线性脚本设计方式是以脚本的方式体现测试用例&#xff0c;是一种非结构化的编码方式&#xff0c;多数采用录制回放的方式&#xff0c;测试工程师通过录制回访的访问对被测系统进行…

在ComfyUI中,IP-Adapter的一大堆模型应该怎么放?

&#x1f381;背景介绍 IP-Adapter有一大堆的模型&#xff0c;那么这个模型在ComfyUI中&#xff0c;这些模型到底应该怎么放呢&#xff1f;这篇文章简单介绍一下。 首先&#xff0c;大家需要到huggingface上找到对应的模型&#xff0c;把所有的模型先下载下来。 huggingface…

vue2 项目认识 vue2 各个文件夹作用 vue工程文件作用 main.js是什么 package.json是什么

1. node_modules : 项目依赖文件夹&#xff0c;相当于java类库。依赖包 2. public 文件夹: 一般放置一些静态资源&#xff08;图片&#xff09;&#xff0c;注意&#xff1a; 放在public文件夹内的文件&#xff0c;webpack打包时候&#xff0c;会原封不动打包到dist文件夹中 …

隐私计算实训营学习二:隐私计算开源如何助力数据要素流通

文章目录 一、数据要素流转与数据内外循环二、数据外循环中的信任焦虑三、数据要素流通对隐私计算的期望四、隐私计算开源助力数据要素流通 一、数据要素流转与数据内外循环 数据要素流转过程(从数据采集加工->到数据价值释放)&#xff1a; 链路主要包括采集、存储、加工、…

Pandas-排序函数sort_values()

Pandas-排序函数sort_values() pandas中的sort_values()函数原理类似于SQL中的order by&#xff0c;可以将数据集依照某个字段中的数据进行排序&#xff0c;该函数即可根据指定列数据也可根据指定行的数据排序。 pandas中的sort_values()函数原理类似于SQL中的order by&#xf…