Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java基准测试工具JMH使用

Java基准测试工具JMH使用

作者头像
全栈程序员站长
发布于 2022-09-18 09:07:33
发布于 2022-09-18 09:07:33
67700
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

JMH,即Java Microbenchmark Harness,这是专门用于进行代码的微基准测试的一套工具API。 JMH 由 OpenJDK/Oracle 里面那群开发了 Java 编译器的大牛们所开发 。何谓 Micro Benchmark 呢? 简单地说就是在 方法层面上的 benchmark,精度可以精确到微秒级。 本文主要介绍了性能基准测试工具 JMH,它可以通过一些功能来规避由 JVM 中的 JIT 或者其他优化对性能测试造成的影响。 Java的基准测试需要注意的几个点:

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

,如果我们要通过JMH进行基准测试的话,直接在我们的pom文件中引入JMH的依赖即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    dependencies { 
   
        jmhCompile project
        jmhCompile 'org.openjdk.jmh:jmh-core:1.24'
        jmhAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.24'
    }

@Fork: 进行 fork 的次数,可用于类或者方法上。如果 fork 数是 2 的话,则 JMH 会 fork 出两个进程来进行测试。 @Threads: 每个测试进程的测试线程数量。 @OutputTimeUnit: 测试结果的时间单位。 @Param 指定某项参数的多种情况,特别适合用来测试一个函数在不同的参数输入的情况下的性能,只能作用在字段上,使用该注解必须定义 @State 注解。

@Setup 必须标示在@State注解的类内部,表示初始化操作 @TearDown 必须表示在@State注解的类内部,表示销毁操作

Level.Trial 只会在个基础测试的前后执行。包括Warmup和Measurement阶段,一共只会执行一次。 Level.Iteration 每次执行记住测试方法的时候都会执行,如果Warmup和Measurement都配置了2次执行的话,那么@Setup和@TearDown配置的方法的执行次数就4次。 Level.Invocation 每个方法执行的前后执行(一般不推荐这么用)

@Benchmark @Benchmark标签是用来标记测试方法的,只有被这个注解标记的话,该方法才会参与基准测试,但是有一个基本的原则就是被@Benchmark标记的方法必须是public的。

@Warmup @Warmup用来配置预热的内容,可用于类或者方法上,越靠近执行方法的地方越准确。一般配置warmup的参数有这些: iterations:预热的次数。 time:每次预热的时间。 timeUnit:时间单位,默认是s。 batchSize:批处理大小,每次操作调用几次方法。 @Measurement 用来控制实际执行的内容 iterations:执行的次数。 time:每次执行的时间。 timeUnit:时间单位,默认是s。 batchSize:批处理大小,每次操作调用几次方法。

@BenchmarkMode @BenchmarkMode主要是表示测量的纬度,有以下这些纬度可供选择:

Mode.Throughput 整体吞吐量,每秒执行了多少次调用,单位为 ops/time Mode.AverageTime 用的平均时间,每次操作的平均时间,单位为 time/op Mode.SampleTime 随机取样,最后输出取样结果的分布 Mode.SingleShotTime 只运行一次,往往同时把 Warmup 次数设为 0,用于测试冷启动时的性能 Mode.All:上面的所有模式都执行一次

Mode.All 运用所有的检测模式 在方法级别指定@BenchmarkMode的时候可以一定指定多个纬度,例如:@BenchmarkMode({Mode.Throughput, Mode.AverageTime, Mode.SampleTime, Mode.SingleShotTime}),代表同时在多个纬度对目标方法进行测量。 @OutputTimeUnit @OutputTimeUnit代表测量的单位,比如秒级别,毫秒级别,微妙级别等等。一般都使用微妙和毫秒级别的稍微多一点。该注解可以用在方法级别和类级别,当用在类级别的时候会被更加精确的方法级别的注解覆盖,原则就是离目标更近的注解更容易生效。

@State 在很多时候我们需要维护一些状态内容,比如在多线程的时候我们会维护一个共享的状态,这个状态值可能会在每隔线程中都一样,也有可能是每个线程都有自己的状态,JMH为我们提供了状态的支持。该注解只能用来标注在类上,因为类作为一个属性的载体。@State的状态值主要有以下几种:

Scope.Benchmark 该状态的意思是会在所有的Benchmark的工作线程中共享变量内容。 Scope.Group 同一个Group的线程可以享有同样的变量 Scope.Thread 每个线程都享有一份变量的副本,线程之间对于变量的修改不会相互影响

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@State(Scope.Benchmark)
@Fork(value = 1)
public class ParseEngineBenchmark { 
   
  	@Param({ 
   "128", "256", "512","1024", "2048", "4096"})
    private int length;
    private byte[] content;
    private byte[] zlibEncode;
    private byte[] zstdEncode;


    @Setup(Level.Trial)
    public void prepare() throws IOException { 
   
         content = RandomStringUtils.randomAlphanumeric(length).getBytes();
        zlibEncode=ZipUtils.compress(content);
        zstdEncode=Zstd.compress(content);
    }

    @TearDown(Level.Trial)
    public void destroy() { 
   
    }

    @Benchmark
    @BenchmarkMode({ 
   Mode.Throughput})
    @OutputTimeUnit(TimeUnit.SECONDS)
    @Warmup(iterations = 2, time = 1)
    @Measurement(iterations = 10, time = 1)
    public byte[] handleZlibCompress() throws IOException { 
   
        return ZipUtils.compress(content);
    }

    public static void main(String[] args) { 
   
        Options opt = new OptionsBuilder(
        )
                .include(ParseEngineBenchmark.class.getSimpleName()).result("result.json")//数据json的跑分结果
                .resultFormat(ResultFormatType.JSON).output("run.log")//输出打印日志
                .build();

        try { 
   
            new Runner(opt).run();
        } catch (RunnerException e) { 
   
            e.printStackTrace();
        }
    }
  }

JMH 可视化除此以外,如果你想将测试结果以图表的形式可视化,可以试下这些网站:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Benchmark                                  (length)   Mode  Cnt         Score        Error  Units
ParseEngineBenchmark.handleCrypto               256  thrpt   10  13042155.579 ± 112897.883  ops/s
ParseEngineBenchmark.handleUnCrypto             256  thrpt   10  11870482.143 ±  41689.274  ops/s
ParseEngineBenchmark.handleZlibCompress         256  thrpt   10    105607.717 ±   7477.906  ops/s
ParseEngineBenchmark.handleZlibUnCompress       256  thrpt   10    298697.795 ±  67420.169  ops/s
ParseEngineBenchmark.handleZstdCompress         256  thrpt   10    304541.271 ±   2214.547  ops/s
ParseEngineBenchmark.handleZstdUnCompress       256  thrpt   10    669493.645 ±   4759.451  ops/s

其中: Mode: thrpt:吞吐量,也可以理解为tps、ops avgt:每次请求的平均耗时 sample:请求样本数量,这次压测一共发了多少个请求 ss:SingleShot除去冷启动,一共执行了多少轮 Cnt、执行次数 Score:得分 Units 单位 Error 误差或者偏差

如果你配置了输出文件,比如我上面的 resul.json ,但是你打开是看不懂的,可以借助两个网站把文件上传进行分析:

JMH Visual Chart,这个项目目前处在实验状态,并没有对所有可能的基准测试结果进行验证,目前它能够比较不同参数下不同方法的性能,未来可以无限的扩展JSON to Chart的转化方法从而支持更多的图表 JMH Visualizer:它是一个功能齐全的可视化项目,只是少了我想要的图表罢了。

进阶: JMH 陷阱在使用 JMH 的过程中,一定要避免一些陷阱。比如 JIT 优化中的死码消除,比如以下代码:@Benchmark public void testStringAdd(Blackhole blackhole) { String a = “”; for (int i = 0; i < length; i++) { a += i; } }JVM 可能会认为变量 a 从来没有使用过,从而进行优化把整个方法内部代码移除掉,这就会影响测试结果。JMH 提供了两种方式避免这种问题,一种是将这个变量作为方法返回值 return a,一种是通过 Blackhole 的 consume 来避免 JIT 的优化消除。其他陷阱还有常量折叠与常量传播、永远不要在测试中写循环、使用 Fork 隔离多个测试方法、方法内联、伪共享与缓存行、分支预测、多线程测试等,感兴趣的可以阅读 https://github.com/lexburner/JMH-samples 了解全部的陷阱。

Q1: gradle Unable to find the resource: /META-INF/BenchmarkList 可能是导入的jar包方式不正常,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        jmhCompile project
        compile 'org.openjdk.jmh:jmh-core:1.24'
        compile 'org.openjdk.jmh:jmh-generator-annprocess:1.24'

改成

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        jmhCompile project
        jmhCompile 'org.openjdk.jmh:jmh-core:1.24'
        jmhAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.24'

Q2: 不能用调试模式,否则会报以下异常:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# Run progress: 0.00% complete, ETA 00:00:24
# Fork: 1 of 1
ERROR: transport error 202: connect failed: Connection refused
ERROR: JDWP Transport dt_socket failed to initialize, TRANSPORT_INIT(510)
JDWP exit error AGENT_ERROR_TRANSPORT_INIT(197): No transports initialized [debugInit.c:750]
<forked VM failed with exit code 2>
<stdout last='20 lines'>
</stdout>
<stderr last='20 lines'>
ERROR: transport error 202: connect failed: Connection refused
ERROR: JDWP Transport dt_socket failed to initialize, TRANSPORT_INIT(510)
JDWP exit error AGENT_ERROR_TRANSPORT_INIT(197): No transports initialized [debugInit.c:750]
</stderr>

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/157425.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
顶级Java才懂的,基准测试JMH!
最近在手写一个ID生成器,需要比较UUID和目前比较流行的 NanoID之间的速度差异,当然也要测一下根据规则自创的ID生成器。
xjjdog
2021/11/19
9100
聊聊springboot项目如何利用jmh来进行基准测试
JMH(Java Microbenchmark Harness)是由OpenJDK团队开发的一个用于Java微基准测试工具套件,主要是基于方法层面的基准测试,精度可以达到纳秒级。它提供了一种标准、可靠且可重复的方式来衡量Java代码的性能,包括方法调用、对象创建以及其他类型的 JVM 级别的操作。JMH 通过生成优化过的字节码来确保基准测试不受常见陷阱的影响,如热身不足、垃圾回收干扰、编译器优化等,从而产生更准确的性能指标
lyb-geek
2024/07/09
4120
聊聊springboot项目如何利用jmh来进行基准测试
Java基准测试工具JMH详解
JMH is a Java harness for building, running, and analysing nano/micro/milli/macro benchmarks written in Java and other languages targetting the JVM. JMH是一种Java工具,用于构建、运行和分析用Java和其他针对JVM的语言编写的nano/micro/mili/macro基准测试。
全栈程序员站长
2022/09/08
1.2K0
别再写 main 方法测试了,太 Low!这才是专业 Java 测试方法!
点击上方“芋道源码”,选择“设为星标” 管她前浪,还是后浪? 能浪的浪,才是好浪! 每天 10:33 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | Java 2021 超神之路,很肝~ 中文详细注释的开源项目 RPC 框架 Dubbo 源码解析 网络应用框架 Netty 源码解析 消息中间件 RocketMQ 源码解析 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析 作业调度中间件 Elastic-Job 源码解析 分布式事务中间件 TCC-Transaction
芋道源码
2022/03/04
2890
架构师Java 并发基准测试神器的-JMH,程序员必看!
在Java编程这个行业里面性能测试这个话题非常庞大,我们可以从网络聊到操作系统,再从操作系统聊到内核,再从内核聊到你怀疑人生有木有。
Java架构师进阶技术
2020/01/31
9750
架构师Java 并发基准测试神器的-JMH,程序员必看!
在java中使用JMH(Java Microbenchmark Harness)做性能测试
在java中使用JMH(Java Microbenchmark Harness)做性能测试
程序那些事
2020/07/08
1K0
JMH - Java 代码性能测试的终极利器、必须掌握
现在的 JVM 已经越来越为智能,它可以在编译阶段、加载阶段、运行阶段对代码进行优化。比如你写了一段不怎么聪明的代码,到了 JVM 这里,它发现几处可以优化的地方,就顺手帮你优化了一把。这对程序的运行固然美妙,却让开发者不能准确了解程序的运行情况。在需要进行性能测试时,如果不知道 JVM 优化细节,可能会导致你的测试结果差之毫厘,失之千里,同样的,Java 诞生之初就有一次编译、随处运行的口号,JVM 提供了底层支持,也提供了内存管理机制,这些机制都会对我们的性能测试结果造成不可预测的影响。
未读代码
2020/08/25
5.9K0
微基准测试框架JMH
最典型的场景就是你想知道两个功能相同的操作到底哪个性能比较好,通常会自己手撸一段代码,前后增加时间,然后对比多次执行的时间。这种做法比较原始,还要自己处理预热等问题。JMH提供了比较丰富的操作。且看如何使用。
李鸿坤
2020/07/17
6280
Java基准测试利器OpenJDK-JMH
什么是基准测试? 这里说道的基准测试Benchmark其实是微基准测试Micro-Benchmark。 简单点说,就是我们看到或听到很多人说什么方式去使用Java的性能好呀,不要猜,动手来测吧! 详细的概念可以参见:https://github.com/google/caliper/wiki/JavaMicrobenchmarks 健壮的Java基准测试 https://www.ibm.com/developerworks/cn/java/j-benchmark1.html https://www.i
斯武丶风晴
2018/05/09
3K0
【连载 72】微基准测试与 JMH 实战
在本书第二部分,我们探讨了基于互联网通信协议(如HTTP、WebSocket、Kafka)的性能测试,通常通过在施压端启动客户端、发起请求、解析响应,分析全链路性能瓶颈并优化。然而,这种方法覆盖整个请求链路,涉及多个方法和代码片段,难以精准定位性能问题。是否存在一种方法,能直接测试特定代码片段的性能,帮助测试工程师快速识别代码中的“坏味道”?
FunTester
2025/07/16
2150
【连载 72】微基准测试与 JMH 实战
别只会 main 方法做测试,太 Low!这才是专业 Java 测试方法!
前言 “"If you cannot measure it, you cannot improve it". 在日常开发中,我们对一些代码的调用或者工具的使用会存在多种选择方式,在不确定他们性能的时候,我们首先想要做的就是去测量它。大多数时候,我们会简单的采用多次计数的方式来测量,来看这个方法的总耗时。 但是,如果熟悉JVM类加载机制的话,应该知道JVM默认的执行模式是JIT编译与解释混合执行。JVM通过热点代码统计分析,识别高频方法的调用、循环体、公共模块等,基于JIT动态编译技术,会将热点代码转换成机
java思维导图
2022/03/21
3580
JMH微基准测试入门案例
这个错误是因为JMH运行需要访问系统的TMP目录,解决办法是: 打开Run Configuration -> Environment Variables -> include system environment viables(勾选)
全栈程序员站长
2022/09/08
4010
JMH微基准测试入门案例
Java性能测试利器:JMH入门与实践|得物技术
在软件开发中,性能测试是不可或缺的一环。但是编写基准测试来正确衡量大型应用程序的一小部分的性能却又非常困难。当基准测试单独执行组件时,JVM或底层硬件可能会对您的组件应用许多优化。当组件作为大型应用程序的一部分运行时,这些优化可能无法应用。因此,实施不当的微基准测试可能会让您相信组件的性能比实际情况更好。编写正确的Java微基准测试通常需要防止JVM和硬件在微基准测试执行期间应用的优化,而这些优化在实际生产系统中是无法应用的。这就是JMH(Java 微基准测试工具)可以帮助您实现的功能。这篇文章我会全面给大家介绍下JMH的各个方面。
得物技术
2024/11/21
3730
别再写 main 方法测试了,太 Low!这才是专业 Java 测试方法!
来源:https://juejin.cn/post/6844903936869007368 前言 "If you cannot measure it, you cannot improve it". 在日常开发中,我们对一些代码的调用或者工具的使用会存在多种选择方式,在不确定他们性能的时候,我们首先想要做的就是去测量它。大多数时候,我们会简单的采用多次计数的方式来测量,来看这个方法的总耗时。 但是,如果熟悉JVM类加载机制的话,应该知道JVM默认的执行模式是JIT编译与解释混合执行。JVM通过热点代码统
java思维导图
2022/03/04
4230
JMH微基准测试框架学习笔记
JMH(Java Microbenchmark Harness)是一个用于编写、构建和运行Java微基准测试的框架。它提供了丰富的注解和工具,用于精确控制测试的执行和结果测量,从而帮助我们深入了解代码的性能特性。
程序员波特
2024/03/21
2550
JMH微基准测试框架学习笔记
使用 JMH 做 Kotlin 的基准测试一. 基准测试二. JMH三. 举例总结
基准测试是一种测量和评估软件性能指标的活动。你可以在某个时候通过基准测试建立一个已知的性能水平(称为基准线),当系统的软硬件环境发生变化之后再进行一次基准测试以确定那些变化对性能的影响。
fengzhizi715
2018/12/26
1.7K1
【进阶之路】Java代码性能调优-基准测试工具JMH(三)
.markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:15px;overflow-x:hidden;color:#333}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{line-height:1.5;margin-top:35px;margin-bottom:10px;padding-bottom:5px}.markdown-body h1{font-size:30px;margin-bottom:5px}.markdown-body h2{padding-bottom:12px;font-size:24px;border-bottom:1px solid #ececec}.markdown-body h3{font-size:18px;padding-bottom:0}.markdown-body h4{font-size:16px}.markdown-body h5{font-size:15px}.markdown-body h6{margin-top:5px}.markdown-body p{line-height:inherit;margin-top:22px;margin-bottom:22px}.markdown-body img{max-width:100%}.markdown-body hr{border:none;border-top:1px solid #ddd;margin-top:32px;margin-bottom:32px}.markdown-body code{word-break:break-word;border-radius:2px;overflow-x:auto;background-color:#fff5f5;color:#ff502c;font-size:.87em;padding:.065em .4em}.markdown-body code,.markdown-body pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}.markdown-body pre{overflow:auto;position:relative;line-height:1.75}.markdown-body pre>code{font-size:12px;padding:15px 12px;margin:0;word-break:normal;display:block;overflow-x:auto;color:#333;background:#f8f8f8}.markdown-body a{text-decoration:none;color:#0269c8;border-bottom:1px solid #d1e9ff}.markdown-body a:active,.markdown-body a:hover{color:#275b8c}.markdown-body table{display:inline-block!important;font-size:12px;width:auto;max-width:100%;overflow:auto;border:1px solid #f6f6f6}.markdown-body thead{background:#f6f6f6;color:#000;text-align:left}.markdown-body tr:nth-child(2n){background-color:#fcfcfc}.markdown-body td,.markdown-body th{padding:12px 7px;line-height:24px}.markdown-body td{min-width:120px}.markdown-body blockquote{color:#666;padding:1px 23px;margin:22px 0;border-left:4px solid #cbcbcb;background-color:#f8f8f8}.markdown-body blockquote:after{display:block;content:""}.markdown-body blockquote>p{margin:10px 0}.markdown-body ol,.markdown-body ul{padding-left:28px}.markdown-body ol li,.markdown-body
南橘
2021/04/02
7790
【进阶之路】Java代码性能调优-基准测试工具JMH(三)
基准测试工具JMH
Java Microbenchmark Harness,简称JMH,由OpenJDK开发,用来构建、运行和分析Java或其他JVM语言代码的微基准测试框架。适合于方法级别的细粒度测试,并不适用于系统之间的链路测试。
johnny666
2024/09/28
2370
JMH实践-代码性能测试工具
概述 JMH,即Java Microbenchmark Harness,是专门用于代码微基准测试的工具套件 JMH比较典型的应用场景有: 想准确的知道某个方法需要执行多长时间,以及执行时间和输入之间的相关性; 对比接口不同实现在给定条件下的吞吐量; 查看多少百分比的请求在多长时间内完成; 基本概念 模式 Throughput: 整体吞吐量,例如“1秒内可以执行多少次调用”。 AverageTime: 调用的平均时间,例如“每次调用平均耗时xxx毫秒”。 SampleTime: 随机取样,最后输出取样结果
老梁
2019/09/10
1.8K0
JMH 一个Java自带的Benchmark
JMH介绍:JDK9 及以后自带的一款可用于软件基准测试的工具 JMH(Java Microbenchmark Harness)。
收心
2022/11/14
1.5K0
JMH 一个Java自带的Benchmark
推荐阅读
相关推荐
顶级Java才懂的,基准测试JMH!
更多 >
交个朋友
加入HAI高性能应用服务器交流群
探索HAI应用新境界 共享实践心得
加入腾讯云技术交流站
洞悉AI新动向 Get大咖技术交流群
加入云原生工作实战群
云原生落地实践 技术难题攻坚探讨
换一批
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验