背景
”If you cannot measure it, you cannot improve it“
在日常开发中,我们对一些代码的调用或者工具的使用会存在多种选择,在不确定他们性能的时候,我们首先想要做的就是先去度量它。大多时候,我们会采用简单的结束时间-开始时间进行测量,这个方法通常不够准确和科学,因为没有经过大量的模拟或者测试。随着JMH的出现,可以很大程度帮助了开发者,为决策提供主要的科学依据以及数据支撑。
JMH 应用场景
-
评估一个方法的不同实现,当你想对比两种不同的数据结构哪种性能更好。 -
评估第三方库的执行性能,当你想比较两种不同的工具包的实现哪个更优(比如Jackson和Gson实现)。 -
度量方法的执行耗时及输入的相关性,当你找到项目热点方法或者代码,想对其进一步进行优化时,也可以使用JMH进行定量分析;
JMH 快速开始
增加Maven依赖
`<!--jmh 基准测试 -->`
`<dependency>`
`<groupId>org.openjdk.jmh</groupId>`
`<artifactId>jmh-core</artifactId>`
`<version>1.23</version>`
`</dependency>`
`<dependency>`
`<groupId>org.openjdk.jmh</groupId>`
`<artifactId>jmh-generator-annprocess</artifactId>`
`<version>1.23</version>`
`<scope>provided</scope>`
`</dependency>`
代码示例
/** 基准模式 {@link Mode} */
@BenchmarkMode(Mode.AverageTime)
// 输出的时间单位
@OutputTimeUnit( TimeUnit.MILLISECONDS )
// 进程数,默认1即可
@Fork(1)
// 预热次数、时长/次,目前配置为:预热五次,每次1秒
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
// 测试次数、时长/次,目前为:执行六次,每次1秒
@Measurement(iterations = 6,time = 1, timeUnit = TimeUnit.SECONDS)
public class TrieBenchmark {
//基准测试
@Benchmark
public void trieInsert_10000() throws Exception {
Trie trie = new Trie();
for (int i = 0; i < 10000 ; i++) {
Thread.sleep(1000);
}
}
public static void main(String[] args) throws RunnerException{
Options options = new OptionsBuilder()
.include(TrieBenchmark.class.getName())
.resultFormat(ResultFormatType.CSV)
.build();
new Runner(options).run();
}
}
JMH详解
什么是JMH
JMH全称 Java Microbenchmark Harness,用于构建、运行和分析以Java和其他基于JVM的其他语言编写的 nano/micro/milli/macro 基准测试的Java工具。
“JMH is a Java harness for building, running, and analysing nano/micro/milli/macro benchmarks written in Java and other languages targetting the JVM.” —官方介绍
相关概念
-
BeachMark:基准测试,主要用来测试一些方法的性能,可以根据不同的参数以不同的单位进行计算(可以使用平均时间作为单位,也可以使用吞吐量作为单位,可以在BenchmarkMode值进行调整)。 -
MIcro Benchmark:简单地说就是在method层面上的benchmark,精度可以精确到微秒级。 -
OPS,Operation Per Second:每秒操作量,是衡量性能的重要指标,数值的性能越好。类似的有:TPS、QPS。 -
Throughput:吞吐量。 -
Warmup:预热,因为JVM的JIT机制的存储,如果某个函数被调用多次之后,JVM会尝试将其编译称为机器码从而提高执行速度。为了让结果更加接近真实情况就需要进行预热。
注解详细介绍
注解 | 注解说明 | 使用方法 |
---|---|---|
@BenchmarkMode | 表示JMH进行Bechmark时使用的模式,测量维度不同与测量的方式不同 | 目前有四种模式:1.Throughput:吞吐量模式,例如”1秒内可以执行多少次调用“,单位是操作数/时间。 2.AverageTime:调用的平均时间,例如”每次调用平均耗时x毫秒“,单位是时间/操作数。 3.SampleTime,随机采样,最后输出采样结果分布,例如”99%的调用在xx毫秒以内“。 4.SingleShotTime:以上模式都是默认一次iteration是1s,唯有SingleShotTime只运行一次。往往把warmup次数设置为0,用于冷启动性能。 |
@OutputTimeUnit | 输出的时间单位 | 即统计时的时间单位 |
@Fork | 进程数,默认1即可 | 用于多进程同时基准测试 |
@Warmup | 在基准测试前先进行的预热行为 | 为了让基准测试结果更加接近真实情况,@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) 即预热5次数、每次1秒 |
@Measurement | 基准测试阶段 | 指定迭代次数与运行时间。@Measurement(iterations = 6,time = 1, timeUnit = TimeUnit.SECONDS) 即执行六次,每次1秒 |
@Threads | Fork面向进程,Threads则是面向线程。 | 如果配置Threads.MAX,则使用和处理器核数相同的线程数 |
@Benchmark | 基准测试方法注解 | 表示该方法是需要进行基准测试的对象 |
@Param | 只能修饰字段,用来测试不同的参数对程序性能的影响,可以配合@State使用 | 常用于多参数基准测试,可以生成不同参数的直接结果分析 |
@Setup | 用于初始化 | 和单元测试JUnit类似,用于基准测试前的初始化动作 |
@TearDown | 基准测试后动作 | 用于资源释放或者资源回收 |
@State | 共享范围 | 用于表示状态共享范围,Benchmark(默认)、Thread,Group三种值 |
图形化结果分析
使用JMH测试的结果,可以二次加工,进行图形化展示。结合图表数据,更加直观。通过运行时,指定输出的格式文件,即可获得相应格式的性能测试结果。
比如下面这行代码,就是指定输出JSON格式的数据。
Options opt = new OptionsBuilder()
.resultFormat(ResultFormatType.JSON)
.build();
JMH支持以下5种格式的结果:
-
TEXT 导出文本文件。 -
CSV 导出csv格式文件。 -
SCSV 导出scsv等格式的文件。 -
JSON 导出成json文件。 -
LATEX 导出到latex,一种基于ΤΕΧ的排版系统。
一般来说,我们导出成CSV文件,直接在Excel中操作,生成相应的图形就可以了。
另外介绍几个可以做图的工具:
JMH Visualizer这里有一个开源的项目(https://jmh.morethan.io/) ,通过导出json文件,上传之后,可得到简单的统计结果。个人认为它的展示方式并不是很好。
jmh-visual-chart
相比较而言,下面这个工具(http://deepoove.com/jmh-visual-chart) ,就相对直观一些。

结束
JMH 进行基准测试的使用过程并不复杂,同为 Java 虚拟机团队开发,准确性毋容置疑。
但是在进行基准测试时还是要注意自己的代码问题,如果编写的要进行测试的代码本身存在问题,那么测试的结果必定是不准的。
了解了 JMH 基准测试之后,可以尝试测试一些常用的工具或者框架的性能如何,看看哪个工具的性能最好,比如 FastJSON 真的比 Jackson / Gson在进行 JSON 转换时更快吗?
参考
https://openjdk.java.net/projects/code-tools/jmh/ http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/ https://lexburner.github.io/java-jmh/ https://segmentfault.com/a/1190000039902797
原文始发于微信公众号(程序猿阿南):JMH – 实践与用法详解
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/22324.html