我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java基准性能测试之JMH的示例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java基准性能测试之JMH的示例分析

这篇文章主要为大家展示了“Java基准性能测试之JMH的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java基准性能测试之JMH的示例分析”这篇文章吧。

一、JMH vs JMeter

JMeter可能是最常用的性能测试工具。它既支持图形界面,也支持命令行,属于黑盒测试的范畴,对非开发人员比较友好,上手也非常容易。图形界面一般用于编写、调试测试用例,而实际的性能测试建议还是在命令行下运行。

很多场景下JMeter和JMH都可以做性能测试,但是对于严格意义上的基准测试来说,只有JMH才适合。JMeter的测试结果精度相对JVM较低、所以JMeter不适合于类级别的基准测试,更适合于对精度要求不高、耗时相对较长的操作。

JMeter测试精度差: JMeter自身框架比较重,举个例子:使用JMH测试一个方法,平均耗时0.01ms,而使用JMeter测试的结果平均耗时20ms,相差200倍。JMeter内置很多采样器:JMeter内置了支持多种网络协议的采样器,可以在不写Java代码的情况下实现很多复杂的测试。JMeter支持集群的方式运行,方便模拟多用户、高并发压力测试。

总结: JMeter适合一些相对耗时的集成功能测试,如API接口的测试。JMH适合于类或者方法的单元测试。

二、JMH基本用法

2.1、创建JMH项目

官方推荐为JMH基准测试创建单独的项目,最简单的创建JMH项目的方法就是基于maven项目原型的方式创建(如果是在windows环境下,需要对org.open.jdk.jmh这样带.的用双引号包裹)。

mvn archetype:generate

          -DinteractiveMode=false

          -DarchetypeGroupId=org.openjdk.jmh

          -DarchetypeArtifactId=jmh-java-benchmark-archetype

          -DarchetypeVersion=1.21

          -DgroupId=com.jenkov

          -DartifactId=first-benchmark

          -Dversion=1.0

可以看到生成的项目pom文件中主要是添加了两个jmh
的依赖和设置了maven-shade-plugin的编译方式(负责把项目的所有依赖jar包打入到目标jar包中,与springboot的实现方式类似)。

<dependencies>        <dependency>            <groupId>org.openjdk.jmh</groupId>            <artifactId>jmh-core</artifactId>            <version>${jmh.version}</version>        </dependency>        <dependency>            <groupId>org.openjdk.jmh</groupId>            <artifactId>jmh-generator-annprocess</artifactId>            <version>${jmh.version}</version>            <scope>provided</scope>        </dependency>    </dependencies>...<plugin>    <groupId>org.apache.maven.plugins</groupId>    <artifactId>maven-shade-plugin</artifactId>    <version>2.2</version>    <executions>        <execution>            <phase>package</phase>            <goals>                <goal>shade</goal>            </goals>            <configuration>                <finalName>${uberjar.name}</finalName>                <transformers>                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">                        <mainClass>org.openjdk.jmh.Main</mainClass>                    </transformer>                </transformers>                <filters>                    <filter>                        <!--                            Shading signed JARs will fail without this.                            http://stackoverflow.com/questions/999489/invalid-signature-file-when-attempting-to-run-a-jar                        -->                        <artifact>*:*</artifact>                        <excludes>                            <exclude>META-INF/*.SF</exclude>                            <exclude>META-INF/*.DSA</exclude>                            <exclude>META-INF/*.RSA</exclude>                        </excludes>                    </filter>                </filters>            </configuration>        </execution>    </executions></plugin>

生成的项目中已经包含了一个class文件MyBenchmark.java,如下:

public class MyBenchmark {    @Benchmark    public void testMethod() {        // This is a demo/sample template for building your JMH benchmarks. Edit as needed.        // Put your benchmark code here.    }}

2.2、编写基准测试代码

在上面生成的MyBenchmark类的testMethod中就可以添加基准测试的java代码,举例如下:测试AtomicInteger的incrementAndGet的基准性能。

public class MyBenchmark {    static AtomicInteger integer = new AtomicInteger();    @Benchmark    public void testMethod() {        // This is a demo/sample template for building your JMH benchmarks. Edit as needed.        // Put your benchmark code here.        integer.incrementAndGet();    }}

2.3、JMH打包、运行

项目打包

mvn clean install

运行生成的目标jar包benchmark.jar:

java -jar benchmark.jar

# JMH version: 1.21

# VM version: JDK 1.8.0_181, Java HotSpot(TM) 64-Bit Server VM, 25.181-b13

# VM invoker: C:\Java\jdk1.8.0_181\jre\bin\java.exe

# VM options: <none>

# Warmup: 5 iterations, 10 s each

# Measurement: 5 iterations, 10 s each

# Timeout: 10 min per iteration

# Threads: 1 thread, will synchronize iterations

# Benchmark mode: Throughput, ops/time

# Benchmark: org.sample.MyBenchmark.testMethod

# Run progress: 0.00% complete, ETA 00:01:40

# Fork: 1 of 1

# Warmup Iteration   1: 81052462.185 ops/s

# Warmup Iteration   2: 80152956.333 ops/s

# Warmup Iteration   3: 81305026.522 ops/s

# Warmup Iteration   4: 81740215.227 ops/s

# Warmup Iteration   5: 82398485.097 ops/s

Iteration   1: 82176523.804 ops/s

Iteration   2: 81818881.730 ops/s

Iteration   3: 82812749.807 ops/s

Iteration   4: 82406672.531 ops/s

Iteration   5: 74270344.512 ops/s

Result "org.sample.MyBenchmark.testMethod":

  80697034.477 ±(99.9%) 13903555.960 ops/s [Average]

  (min, avg, max) = (74270344.512, 80697034.477, 82812749.807), stdev = 3610709.330

  CI (99.9%): [66793478.517, 94600590.437] (assumes normal distribution)

# Run complete. Total time: 00:01:41

REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on

why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial

experiments, perform baseline and negative tests that provide experimental control, make sure

the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.

Do not assume the numbers tell you what you want them to tell.

Benchmark                Mode  Cnt         Score          Error  Units

MyBenchmark.testMethod  thrpt    5  80697034.477 ± 13903555.960  ops/s

从上面的日志我们大致可以了解到 JMH的基准测试主要经历了下面几个过程:

打印本次测试的配置,warmup:5轮;measurement:5轮;每轮:10s;启动1个线程做测试;基准测试指标:吞吐量(throughput,单位是s);测试方法MyBenchmark.testMethod

启动一个JVM进程做基准测试(也可以设置启动多个进程,减少随机因素的误差影响)

在JVM进程中先执行了5轮的预热(warmup),每轮10s,总共50s的预热时间。预热的数据不作为基准测试的参考。

测试了5轮,每轮10s,总共50s的测试时间

汇总测试数据、生成结果报表。最终结论是吞吐量(80697034.477 ±13903555.960 ops/s),其中80697034.477 是结果,13903555.960是误差范围。

2.4、JMH与Springboot

在对Springboot项目做JMH基准测试时可能会因为maven-shade-plugin插件的问题打包报错,需要在JMH的maven-shade-plugin的插件配置中添加id即可。项目的pom可能如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <parent>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-parent</artifactId>        <version>2.0.7.RELEASE</version>        <relativePath/>    </parent>...<plugin>    <groupId>org.apache.maven.plugins</groupId>    <artifactId>maven-shade-plugin</artifactId>    <version>2.2</version>    <executions>        <execution>            <!-- 需要在此处添加一个id标签,否则mvn package时会报错 -->            <id>shade-all-dependency-jar</id>            <phase>package</phase>            <goals>                <goal>shade</goal>            </goals>            <configuration>                ...            </configuration>        </execution>    </executions></plugin>...</project>

在测试代码中正常基于SpringBootApplication构建ConfigurableApplicationContext从而获取bean的方式获取对象测试即可。

public class StringRedisTemplateBenchmark  {    StringRedisTemplate redisTemplate;                @Setup(Level.Trial)    public void setUp() {        redisTemplate = SpringApplication.run(SpringBootApplicationClass.class).getBean(StringRedisTemplate.class);    }        @Benchmark    public void testGet() {        redisTemplate.opsForValue().get("testkey");    }}@SpringBootApplicationpublic class SpringBootApplicationClass {}

application.properties

lettuce.pool.maxTotal=50lettuce.pool.maxIdle=10lettuce.pool.minIdle=0lettuce.sentinel.master=mymasterlettuce.sentinel.nodes=10.xx.xx.xx:26379,10.xx.xx.xx:26379lettuce.password=xxxxxx

三、JMH注解

JMH测试的相关配置大多是通过注解的方式体现的。

具体每个注解的使用实例也可以参考官网

http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/class="lazy" data-src/main/java/org/openjdk/jmh/samples/

3.1、JMH Benchmark Modes

JMH benchmark支持如下几种测试模式:

  • Throughput: 吞吐量,测试每秒可以执行操作的次数

  • Average Time: 平均耗时,测试单次操作的平均耗时

  • Sample Time:采样耗时,测试单次操作的耗时,包括最大、最小耗时,已经百分位耗时等

  • Single Shot Time: 只计算一次的耗时,一般用来测试冷启动的性能(不设置JVM预热)

  • All: 测试上面的所有指标

默认的benchmark mode是Throughput,可以通过注解的方式设置BenchmarkMode,注解支持放在类或方法上。如下所示设置了Throughput和SampleTime两个Benchmark mode。

@BenchmarkMode({Mode.Throughput, Mode.SampleTime})public class MyBenchmark {    static AtomicInteger integer = new AtomicInteger();    @Benchmark    public void testMethod() {        // This is a demo/sample template for building your JMH benchmarks. Edit as needed.        // Put your benchmark code here.        integer.incrementAndGet();    }}

3.2、Benchmark Time Units

JMH支持设置打印基准测试结果的时间单位,通过@OutputTimeUnit注解的方式设置。

@OutputTimeUnit(TimeUnit.SECONDS)public class MyBenchmark {    static AtomicInteger integer = new AtomicInteger();    @Benchmark    public void testMethod() {        integer.incrementAndGet();    }}

3.3、Benchmark State

有时候我们在做基准测试的时候会需要使用一些变量、字段,@State注解是用来配置这些变量的生命周期,@State注解可以放在类上,然后在基准测试方法中可以通过参数的方式把该类对象作为参数使用。@State支持的生命周期类型:

  • Benchmark: 整个基准测试的生命周期,多个线程共用同一份实例对象。该类内部的@Setup @TearDown注解的方法可能会被任一个线程执行,但是只会执行一次。

  • Group: 每一个Group内部共享同一个实例,需要配合@Group @GroupThread使用。该类内部的@Setup @TearDown注解的方法可能会该Group内的任一个线程执行,但是只会执行一次。

  • Thread:每个线程的实例都是不同的、唯一的。该类内部的@Setup @TearDown注解的方法只会被当前线程执行,而且只会执行一次。

被@State标示的类必须满足如下两个要求:

类必须是public的

必须有无参构造函数

3.4、State Object @Setup @TearDown

在@Scope注解标示的类的方法上可以添加@Setup和@TearDwon注解。@Setup:用来标示在Benchmark方法使用State对象之前需要执行的操作。@TearDown:用来标示在Benchmark方法之后需要对State对象执行的操作。
如下示例:

@OutputTimeUnit(TimeUnit.SECONDS)public class MyBenchmark {        @Benchmark    public void testMethod(TestAddAndGetState state) {        state.getInteger().incrementAndGet();    }    @State(Scope.Benchmark)    public static class TestAddAndGetState {        private AtomicInteger integer;        @Setup(Level.Iteration)        public void setup() {            integer = new AtomicInteger();        }        public AtomicInteger getInteger() {            return integer;        }    }}

@Setup、@TearDown支持设置Level级别,Level有三个值:

  • Trial: 每次benchmark前/后执行一次,每次benchmark会包含多轮(Iteration)

  • Iteration: 每轮执行前/后执行一次

  • Invocation: 每次调用测试的方法前/后都执行一次,这个执行频率会很高,一般用不上。

3.5、Fork

@Fork注解用来设置启动的JVM进程数量,多个进程是串行的方式启动的,多个进程可以减少偶发因素对测试结果的影响。

3.6、Thread

@Thread用来配置执行测试启动的线程数量

3.7、Warmup

@Warmup 用来配置预热的时间,如下所示配置预热五轮,每轮1second,也就是说总共会预热5s左右,在这5s内会不停的循环调用测试方法,但是预热时的数据不作为测试结果参考。

@Warmup(iterations = 5, time = 1)

3.8、Measurement

@Measurement用来配置基准测试的时间,如下所示配置预热10轮,每轮1second,也就是说总共会测试10s左右,在这10s内会不停的循环调用测试方法,同事测试数据会被基准测试结果参考。

@Measurement(iterations = 5, time = 1)

四、输出测试结果

jmh支持多种格式的结果输出text, csv, scsv, json, latex

如下打印出json格式的:

java -jar benchmark.jar -rf json

以上是“Java基准性能测试之JMH的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java基准性能测试之JMH的示例分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java基准性能测试之JMH的示例分析

这篇文章主要为大家展示了“Java基准性能测试之JMH的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java基准性能测试之JMH的示例分析”这篇文章吧。一、JMH vs JMeterJ
2023-06-20

Java使用JMH进行基准性能测试分析

本篇内容主要讲解“Java使用JMH进行基准性能测试分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java使用JMH进行基准性能测试分析”吧!一、前言在日常开发工作当中,开发人员可能有这些困
2023-06-25

Go函数性能优化:基准测试与性能分析方法

了解 go 函数性能优化至关重要,可以通过以下方法实现:基准测试:使用 go 的 testing 包测量执行时间和资源消耗,例如基准测试字符串连接策略。性能分析:使用 runtime/pprof 包生成函数调用图,通过 go tool pp
Go函数性能优化:基准测试与性能分析方法
2024-05-03

Go语言单元测试与性能测试示例分析

这篇文章主要讲解了“Go语言单元测试与性能测试示例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Go语言单元测试与性能测试示例分析”吧!概述测试不是Go语言独有的,其实在很多语言都有测试
2023-06-25

Java基础之Maven的示例分析

这篇文章将为大家详细讲解有关Java基础之Maven的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、Maven是什么?Maven是一个跨平台的项目管理工具。作为Apache组织的一个颇为成功的
2023-06-15

java基础之this的示例分析

小编给大家分享一下java基础之this的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1、this关键字首先需要提醒的是,在整个Java之中,this是
2023-06-20

java内部测试类的示例分析

这篇文章将为大家详细讲解有关java内部测试类的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。我们一般使用的java内部类有4种形式:一般内部类、局部内部类、匿名内部类、静态内部类。以下是我作的一
2023-05-30

c++性能测试工具之计算时间复杂度的示例分析

小编给大家分享一下c++性能测试工具之计算时间复杂度的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!google benchmark已经为我们提供了类似的功能,而且使用相当简单。具体的解释在后面,我们先来看几个例子
2023-06-15

网站测试重要性的示例分析

这篇文章将为大家详细讲解有关网站测试重要性的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。网站不稳定的情况我们在浏览网站时,在浏览的过程中,有时会出现错误代码提示,或许是连接不上,或者是找不到所要
2023-06-10

stress性能测试模拟CPU使用100%的示例分析

这篇文章给大家分享的是有关stress性能测试模拟CPU使用100%的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。(1)安装stress解压:tar -xzvf stress-1.0.4.tar.gz.
2023-06-25

基于SpringBoot Mock单元测试的示例分析

小编给大家分享一下基于SpringBoot Mock单元测试的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!Junit中的基本注解:@Test:使用该注解标注的public void方法会表示为一个测试方法;@Be
2023-06-25

java基础之方法的示例分析

这篇文章将为大家详细讲解有关java基础之方法的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。JAVA 异常分类及处理 异常分类Throwable 是 Java 语言中所有错误或异常的超类。下一层
2023-06-20

java基础之多态的示例分析

小编给大家分享一下java基础之多态的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1、多态性多态性是面向对象的最后一个特征,它本身主要分为两个方面: 方
2023-06-20

java基础之string类的示例分析

这篇文章主要为大家展示了“java基础之string类的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“java基础之string类的示例分析”这篇文章吧。1、String类1.1两种对象
2023-06-20

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录