JMH简介
JMH是新的microbenchmark(微基准测试)框架(2013年首次发布)。与其他众多框架相比它的特色优势在于,它是由Oracle实现JIT的相同人员开发的。特别是我想提一下Aleksey Shipilev和他优秀的博客文章。JMH可能与最新的Oracle JRE同步,其结果可信度很高。
HelloWorld
学习JMH的第一步当然是完成一个简单的Hello World。如何来完成呢?满足3个条件:
- 设置JMH-core和jmh-generator-annprocess的maven依赖
- 使用
@Benchmark
来注解测试方法 - 安装JMH插件(IDEA)
|
|
然后写一个测试例子,参考于JMH Samples:
|
|
这里来解释代码的意义,首先排除JMH相关的注解:
|
|
这样就好理解了,BaselineBenchmarks类中有1个int的字段i及两个方法noop()
和increment()
其中increment()
方法中调用了i++
。
好了接下来说明JMH的注解,首先是@Benchmark
, 这个很好理解代表该注解的方法是一个基准测试方法,你可以想象和单元测试的@Test
一样。
@BenchmarkMode
注解表示使用特定的测试模式,相关参数见下表:
名称 | 描述 |
---|---|
Mode.Throughput | 计算一个时间单位内操作数量 |
Mode.AverageTime | 计算平均运行时间 |
Mode.SampleTime | 计算一个方法的运行时间(包括百分位) |
Mode.SingleShotTime | 方法仅运行一次(用于冷测试模式)。或者特定批量大小的迭代多次运行(具体查看后面的@Measurement 注解)——这种情况下JMH将计算批处理运行时间(一次批处理所有调用的总时间) |
这些模式的任意组合 | 可以指定这些模式的任意组合——该测试运行多次(取决于请求模式的数量) |
Mode.All | 所有模式依次运行 |
@OutputTimeUnit
是用来指定时间单位,它用一个标准Java类型java.util.concurrent.TimeUnit作为参数。如果在一个测试中指定了多种测试模式,给定的时间单位将用于所有的测试。
@State
注解定义了给定类实例的可用范围。JMH可以在多线程同时运行的环境测试,因此需要选择正确的状态。
名称 | 描述 |
---|---|
Scope.Thread | 默认状态。实例将分配给运行给定测试的每个线程。 |
Scope.Benchmark | 运行相同测试的所有线程将共享实例。可以用来测试状态对象的多线程性能(或者仅标记该范围的基准)。 |
Scope.Group | 实例分配给每个线程组(查看后面的线程组部分) |