.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 ul li{margin-bottom:0;list-style:inherit}.markdown-body ol li .task-list-item,.markdown-body ul li .task-list-item{list-style:none}.markdown-body ol li .task-list-item ol,.markdown-body ol li .task-list-item ul,.markdown-body ul li .task-list-item ol,.markdown-body ul li .task-list-item ul{margin-top:0}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:3px}.markdown-body ol li{padding-left:6px}.markdown-body .contains-task-list{padding-left:0}.markdown-body .task-list-item{list-style:none}@media (max-width:720px){.markdown-body h1{font-size:24px}.markdown-body h2{font-size:20px}.markdown-body h3{font-size:18px}}
导言
大家好,我是南橘,从接触java到现在也有差不多两年时间了,两年时间,从一名连java有几种数据结构都不懂超级小白,到现在懂了一点点的进阶小白,学到了不少的东西。知识越分享越值钱,我这段时间总结(包括从别的大佬那边学习,引用)了一些平常学习和面试中的重点(自我认为),希望给大家带来一些帮助
前两章介绍了JAVA代码调优的一些方法,这一章我们就一起学习一下代码调优时的测试工具JMH
一、JMH介绍
JMH(Java Microbenchmark Harness)是用于代码微基准测试的工具套件,主要是基于方法层面的基准测试,精度可以达到纳秒级。
基准测试是指通过设计科学的测试方法、测试工具和测试系统,实现对一类测试对象的某项性能指标进行定量的和可对比的测试。
应用场景
- 想准确地知道某个方法需要执行多长时间,以及执行时间和输入之间的相关性
- 对比接口不同实现在给定条件下的吞吐量
- 查看多少百分比的请求在多长时间内完成
具体内容可以查看JMH的官方DEMO JMH官方DEMO
二、JMH使用注解总结
1、BenchmarkMode
JMH测试时运行的模式模式
类型 | 效用 |
---|---|
Mode.All | 所有模式依次运行(测试时使用最多) |
Mode.Throughput | 每段时间执行的次数,一般是秒 |
Mode.AverageTime | 平均时间,每次操作的平均耗时 |
Mode.SampleTime | 在测试中,随机进行采样执行的时间 |
Mode.SingleShotTime | 在每次执行中计算耗时 |
可以组合使用
2、OutputTimeUnit
用来决定JMH测试的指定时间单位,它需要一个标准Java类型java.util.concurrent.TimeUnit作为参数。
3、Warmup
进行基准测试前需要进行预热。
在进行微基准测试时,我们想要测试的是“程序被JVM编译成机器代码(而不是直接执行字节码)”的执行速度。为了让JVM把要测试的代码编译成机器码,我们可能需要把要测试的代码进行“预热处理”(就是先跑几回,或十几回等,当运行的次多了,JVM就会生成机器码),JMH就提供“预热处理”等一系列的处理。
4、State
注解定义了给定类实例的可用范围
5、Measurement
给定基本的测试参数。
- iterations进行测试的轮次
- time每轮进行的时长
- timeUnit时长单位
6、Fork
需要运行的试验(迭代集合)数量。每个试验运行在单独的JVM进程中。也可以指定(额外的)JVM参数。
7、Threads
该测试使用的线程数。默认是Runtime.getRuntime().availableProcessors()
8、Benchmark
方法注解,表示该方法是需要进行 benchmark 的对象。
9、Setup
方法注解,会在执行 benchmark 之前被执行,正如其名,主要用于初始化。
10、TearDown
与@Setup 相对的,会在所有 benchmark 执行结束以后执行,主要用于资源的回收等。
11、Param
成员注解,可以用来指定某项参数的多种情况。特别适合用来测试一个函数在不同的参数输入的情况下的性能。@Param注解接收一个String数组,在@setup方法执行前转化为为对应的数据类型。多个@Param注解的成员之间是乘积关系,譬如有两个用@Param注解的字段,第一个有5个值,第二个字段有2个值,那么每个测试方法会跑5*2=10次。
三、JMH使用
1、添加依赖
因为 JMH 是 JDK9 自带的,如果是 JDK9 之前的版本需要加入依赖(人人都用JAVA8)
代码语言:javascript复制
org.openjdk.jmh
jmh-core
()
org.openjdk.jmh
jmh-generator-annprocess
2、代码演示
先找到之前做过测试的代码
代码语言:javascript复制public class CommonUtils {
static int cacheSize =1024;
static String[] caches =new String[cacheSize];
static {
for(int i=0;i复制代码
点击运行得出结论
- 1、我们可以分别看到 两个方法依次对Param里的参数进行了测试。
- 2、Mode里的参数thrpt是Throughput的简写
- 3、Cnt表示测试了三遍
- 4、Score通过对Mode的参数的解读,得出每毫秒执行的次数(ops/ms)
- 5、Error表示测试的误差,测试轮次越多误差越小(大概吧)
四、JMH 插件
大家还可以通过 IDEA 安装 JMH 插件使 JMH 更容易实现基准测试,在 IDEA 中点击 File->Settings...->Plugins,然后搜索 jmh,选择安装 JMH plugin:
这个插件可以让我们能够以 JUnit 相同的方式使用 JMH,主要功能如下:
- 自动生成带有 @Benchmark 的方法像 JUnit 一样
- 运行单独的 Benchmark 方法
- 运行类中所有的 Benchmark 方法
比如可以通过右键点击 Generate.,选择操作 Generate JMH benchmark 就可以生成一个带有 @Benchmark 的方法。
还有将光标移动到方法声明并调用 Run 操作就运行一个单独的 Benchmark 方法。
将光标移到类名所在行,右键点击 Run 运行,该类下的所有被 @Benchmark 注解的方法都会被执行。
结语
我们在编写代码的过程中,稍稍一注意,就能全面提升代码的性能。本文主要介绍了性能基准测试工具 JMH,它可以通过一些功能来规避由 JVM 中的 JIT 或者其他优化对性能测试造成的影响。只需要将待测的业务逻辑用 @Benchmark 注解标识,就可以让 JMH 的注解处理器自动生成真正的性能测试代码,以及相应的性能测试配置文件。
同时需要思维导图的话,可以联系我,毕竟知识越分享越香!