JMH初体验

  • 时间:
  • 来源:互联网
  • 文章标签:

什么是JMH

JMH是 Java Microbenchmark Harness 的缩写。中文意思大致是 “JAVA 微基准测试套件”。

基准测试是指通过设计科学的测试方法、测试工具和测试系统,实现对一类测试对象的某项性能指标进行定量的和可对比的测试。——百度百科

为什么要使用 JMH

基准测试的特质有如下几种:

  1. 可重复性:可进行重复性的测试,这样做有利于比较每次的测试结果,得到性能结果的长期变化趋势,为系统调优和上线前的容量规划做参考。
  2. 可观测性:通过全方位的监控(包括测试开始到结束,执行机、服务器、数据库),及时了解和分析测试过程发生了什么。
  3. 可展示性:相关人员可以直观明了的了解测试结果(web界面、仪表盘、折线图树状图等形式)。
  4. 真实性:测试的结果反映了客户体验到的真实的情况(真实准确的业务场景+与生产一致的配置+合理正确的测试方法)。
  5. 可执行性:相关人员可以快速的进行测试验证修改调优(可定位可分析)。

可见要做一次符合特质的基准测试,是很繁琐也很困难的。外界因素很容易影响到最终的测试结果。特别对于 JAVA的基准测试。

有些人认为Java是C++编写的,一般来说Java编写的程序不太可能比 C++编写的代码运行效率更好。但是Java在某些场景的确要比 C++运行的更高效。不要觉得天方夜谭。其实JVM随着这些年的发展,已经变得很先进,它会在运行期间不断的去优化。

这对于我们程序来说是好事,但是对于性能测试就头疼的。你运行的次数与时间不同可能获得的结果也不同,很难获得一个比较稳定的结果。对于这种情况,有一个解决办法就是大量的重复调用,并且在真正测试前还要进行一定的预热,使结果尽可能的准确。

如何使用 JMH

导入依赖

新建一个Maven工程,导入依赖:

<!-- Java Microbenchmark Harness -->
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-core</artifactId>
    <version>1.19</version>
</dependency>
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-generator-annprocess</artifactId>
    <version>1.19</version>
</dependency>

基准测试代码

package com.lun.string;

import org.openjdk.jmh.annotations.Benchmark;

public class StringConnectBenchmark {
    /**
     * 字符串拼接之 StringBuilder 基准测试
     */
    @Benchmark
    public void testStringBuilder() {
        print(new StringBuilder().append(1).append(2).append(3).toString());
    }

    /**
     * 字符串拼接之直接相加基准测试
     */
    @Benchmark
    public void testStringAdd() {
        print(new String()+ 1 + 2 + 3);
    }

    /**
     * 字符串拼接之String Concat基准测试
     */
    @Benchmark
    public void testStringConcat() {
        print(new String().concat("1").concat("2").concat("3"));
    }

    /**
     * 字符串拼接之 StringBuffer 基准测试
     */
    @Benchmark
    public void testStringBuffer() {
        print(new StringBuffer().append(1).append(2).append(3).toString());
    }

    /**
     * 字符串拼接之 StringFormat 基准测试
     */
    @Benchmark
    public void testStringFormat(){
        print(String.format("%s%s%s", 1, 2, 3));
    }

    public void print(String str) {

    }
}

运行基准测试代码

package com.lun.string;

import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

public class StringBuilderRunner {
	
	public static void main(String[] args) throws RunnerException {
		Options opt = new OptionsBuilder()
				// 导入要测试的类
				.include(StringConnectBenchmark.class.getSimpleName())
				// 预热5轮
				.warmupIterations(5)
				// 度量10轮
				.measurementIterations(10)
				.mode(Mode.Throughput)
				.forks(3)
				.build();

		new Runner(opt).run();

	}
}

运行结果

...
# Run progress: 93.33% complete, ETA 00:00:17
# Fork: 3 of 3
# Warmup Iteration   1: 168644.227 ops/s
# Warmup Iteration   2: 406543.452 ops/s
# Warmup Iteration   3: 417524.283 ops/s
# Warmup Iteration   4: 453008.474 ops/s
# Warmup Iteration   5: 450343.882 ops/s
Iteration   1: 452407.964 ops/s
Iteration   2: 454286.433 ops/s
Iteration   3: 446131.016 ops/s
Iteration   4: 449042.238 ops/s
Iteration   5: 457997.034 ops/s
Iteration   6: 450785.925 ops/s
Iteration   7: 450866.167 ops/s
Iteration   8: 439266.876 ops/s
Iteration   9: 453702.384 ops/s
Iteration  10: 451028.848 ops/s


Result "com.lun.string.StringConnectBenchmark.testStringFormat":
  441747.293 ±(99.9%) 15980.806 ops/s [Average]
  (min, avg, max) = (342074.817, 441747.293, 463951.126), stdev = 23919.319
  CI (99.9%): [425766.487, 457728.099] (assumes normal distribution)


# Run complete. Total time: 00:04:23

Benchmark                                  Mode  Cnt         Score         Error  Units
StringConnectBenchmark.testStringAdd      thrpt   30  11809268.588 ±  766758.418  ops/s
StringConnectBenchmark.testStringBuffer   thrpt   30  68501244.128 ± 1373528.962  ops/s
StringConnectBenchmark.testStringBuilder  thrpt   30  49564682.559 ± 7821622.523  ops/s
StringConnectBenchmark.testStringConcat   thrpt   30  14246208.232 ±  443906.557  ops/s
StringConnectBenchmark.testStringFormat   thrpt   30    441747.293 ±   15980.806  ops/s

Score分数越高越好

参考资料

  1. 【基准测试】JMH 简单入门
  2. Java Micro Benchmark with JMH

本文链接http://www.taodudu.cc/news/show-1781978.html