Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >JMH探索

JMH探索

作者头像
全栈程序员站长
发布于 2022-09-18 08:47:07
发布于 2022-09-18 08:47:07
4480
举报

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

JMH探索

JMH基本介绍

什么是JMH

JMH,即Java Microbenchmark Harness,是专门用于Java代码微基准测试的工具套件。由OpenJDK开发的,主要是基于方法层面的基准测试,精度可以达到纳秒级。当定位到热点方法,希望进一步优化方法性能的时候,就可以使用JMH对优化的结果进行量化分析。

JMH入门

使用maven项目演示,这里使用最新版本1.28

代码语言:javascript
AI代码解释
复制
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-core</artifactId>
    <version>1.28</version>
</dependency>
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-generator-annprocess</artifactId>
    <version>1.28</version>
    <scope>provided</scope>
</dependency>
代码语言:javascript
AI代码解释
复制
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public class JMHSample_01_HelloWorld { 
   
    @Benchmark
    public void wellHelloThere() { 
   
        // this method was intentionally left blank.
    }

    public static void main(String[] args) throws RunnerException { 
   
        Options opt = new OptionsBuilder()
                .include(JMHSample_01_HelloWorld.class.getSimpleName())
                .build();

        new Runner(opt).run();
    }
}

以上便是官方最简单的测试,其中度量的方法为wellHelloThere,执行后可判断出该方法的测试基础信息(个人不建议执行,默认的参数执行的时间太长)。

JMH的基本概念和配置

我们再看一个稍微复杂的例子,比对int和Integer的性能:

代码语言:javascript
AI代码解释
复制
@BenchmarkMode(Mode.Throughput)
@Warmup(iterations = 1, time = 1)
@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
@Threads(1)
@Fork(1)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MMBenchmarkInt {

    @Benchmark
    public int mmTestInt() {
        int result = 0;
        for (int i = 0; i < 100; i++) {
            result += i;
        }
        return result;
    }

    @Benchmark
    public Integer mmTestInteger() {
        Integer result = 0;
        for (int i = 0; i < 100; i++) {
            result += i;
        }
        return result;
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(MMBenchmarkInt.class.getSimpleName())
                .build();

        new Runner(opt).run();
    }
}
基本标签介绍

@BenchmarkMode为使用模式,参数Mode表示JMH的测量方式和角度,有以下4种:

  • Throughput:吞吐量,单位时间内可以执行多少次。
  • AverageTime:平均时间。
  • SampleTime:随机取样,最后输出取样结果的分布,如99%的调用在xx毫秒内,99.99的调用在xx毫秒内。
  • SingleShotTime:只运行一次,一般用于测试冷启动的消耗时间。
  • All:统计前面所有的指标。

@Warmup为配置预热次数,本例是每次执行1秒,执行1次。


@Measurement为配置执行次数,本例为每次执行1秒,执行3次。在性能对比时,采用默认1秒即可,如果用jvisualvm来做性能监控,则可指定一个较长的运行时间。


@Threads为配置多少个线程同时执行,


@Fork为启动单独的JVM进程分别测试每个方法,这里指定为每个方法启动1个进程。


@OutputTimeUnit为统计结果的时间单元,本例是TImeUnit.NANOSECONDS,运行后会看到输出结果是统计的每纳秒的吞吐量。


控制台输出

开始会输出本次测试的参数:预测次数、执行次数、测量模式、测试的方法等等。

代码语言:javascript
AI代码解释
复制
# Warmup: 1 iterations, 1 s each
# Measurement: 3 iterations, 1 ns each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: com.mm.mmspringboot.test.MMBenchmarkString.mmTest1

接着,这里的Fork表示子进程,我们只配置了一个,因此只有一个进程的执行结果;然后下面包含了Warmup(预热1次,每次1秒);再下面为Measurement(执行3次,每次1秒)。

代码语言:javascript
AI代码解释
复制
# Run progress: 0.00% complete, ETA 00:00:08
# Fork: 1 of 1
# Warmup Iteration   1: 0.462 ops/ns
Iteration   1: 0.455 ops/ns
Iteration   2: 0.595 ops/ns
Iteration   3: 0.592 ops/ns

执行完每个测试方法,都会打印一个每个方法的汇总信息。

汇总信息包含了多次测试后的最小值、最大值、均值、标准差(stdev)和置信区间(CI,Confidence interval)。

代码语言:javascript
AI代码解释
复制
Result "com.mm.mmspringboot.test.MMBenchmarkInt.mmTestInt":
  0.547 ±(99.9%) 1.459 ops/ns [Average]
  (min, avg, max) = (0.455, 0.547, 0.595), stdev = 0.080
  CI (99.9%): [0, 2.007] (assumes normal distribution)

最后,JMH会为我们打印出多个方法的测试对比结果,可看出int比Integer的吞吐量高许多:

代码语言:javascript
AI代码解释
复制
Benchmark                      Mode  Cnt  Score   Error   Units
MMBenchmarkInt.mmTestInt      thrpt    3  0.547 ± 1.459  ops/ns
MMBenchmarkInt.mmTestInteger  thrpt    3  0.004 ± 0.002  ops/ns

该例中测量模式为吞吐量

常用模式(Mode)

上例中,我们使用的测试模式为Mode.Throughput(吞吐量),单位为ops(Operation Per Second),结合输出单位,就是每纳秒的吞吐量。

下面我们来看看其他测量模式的比对结果,Mode.AverageTime(平局时间),单位为ns/op,即每次吞吐的纳秒,结果如下:

代码语言:javascript
AI代码解释
复制
Benchmark                     Mode  Cnt    Score     Error  Units
MMBenchmarkInt.mmTestInt      avgt    3    1.842 ±   4.844  ns/op
MMBenchmarkInt.mmTestInteger  avgt    3  261.227 ± 380.288  ns/op

Mode.SampleTime(随机采样),可看到分布图(如p0.99的Score为100,表名了99%的每次吞吐的纳秒在100以内),分布结果如下:

迭代(Iteration)

可看到在Warmup(预热)和Measurement(执行)中都用到了iterations,它是JMH的测量单位,每次迭代都会统计出相关的吞吐量、平均时间等。

预热(Warmup)

由于Java虚拟机的JIT的存在,同一个方法在JIT编译前后的时间将会不同。通常只考虑方法在JIT编译后的性能,所以需要预热。

配置类(Options)

配置类用于指定一些参数,如指定测试类(include)、使用的进程个数(fork)、执行迭代次数(measurementIterations)等等。

如上例中的注解属性:

代码语言:javascript
AI代码解释
复制
@BenchmarkMode(Mode.Throughput)
@Warmup(iterations = 1, time = 1)
@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
@Threads(1)
@Fork(1)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MMBenchmarkProperties {

完全可在配置类里声明:

代码语言:javascript
AI代码解释
复制
public static void main(String[] args) throws RunnerException {
    Options opt = new OptionsBuilder()
            .include(MMBenchmarkProperties.class.getSimpleName())
            .mode(Mode.Throughput)
            .warmupIterations(1).warmupTime(new TimeValue(1, TimeUnit.SECONDS))
            .measurementIterations(3).measurementTime(new TimeValue(1, TimeUnit.SECONDS))
            .threads(1)
            .forks(1)
            .timeUnit(TimeUnit.NANOSECONDS)
            .build();

    new Runner(opt).run();
}
状态(State)

通过State指定一个对象的作用范围(Scope),取值如下:

  • Scope.Benchmark:基准测试范围,多个线程共享一个实例,可用于测试多线程共享下的性能。
  • Scope.Thread:默认的 State,每个测试线程分配一个实例。
  • Scope.Group:同一个线程在同一个 group 里共享实例。

使用官方的例子改改,测试如下:

代码语言:javascript
AI代码解释
复制
@BenchmarkMode(Mode.Throughput)
@Warmup(iterations = 1, time = 1)
@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
@Threads(5)
@Fork(1)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class JMHSample_03_States {
    @State(Scope.Benchmark)
    public static class BenchmarkState {
        volatile double x = Math.PI;
    }

    @State(Scope.Thread)
    public static class ThreadState {
        volatile double x = Math.PI;
    }

    @Benchmark
    public void ThreadScope(BenchmarkState state) {
        state.x++;
    }

    @Benchmark
    public void BenchmarkScope(ThreadState state) {
        state.x++;
    }

    @State(Scope.Group)
    public static class GroupState {
        volatile double x = Math.PI;
    }

    @Benchmark
    @Group("mmGroup")
    @GroupThreads(4)
    public double GroupScopeRead(GroupState state) {
        return state.x;
    }

    @Benchmark
    @Group("mmGroup")
    @GroupThreads(1)
    public void GroupScopeWrite(GroupState state) {
        state.x++;
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JMHSample_03_States.class.getSimpleName())
                .build();

        new Runner(opt).run();
    }
}
代码语言:javascript
AI代码解释
复制
Benchmark                Mode  Cnt  Score   Error   Units
BenchmarkScope           thrpt    3  0.871 ± 0.054  ops/ns
ThreadScope              thrpt    3  0.042 ± 0.002  ops/ns
mmGroup                  thrpt    3  0.333 ± 0.033  ops/ns
mmGroup:GroupScopeRead   thrpt    3  0.294 ± 0.038  ops/ns
mmGroup:GroupScopeWrite  thrpt    3  0.039 ± 0.007  ops/ns

控制台输出中,BenchmarkScope和ThreadScope代表着多线程和单线程下的比对结果。mmGroup代表着是一个组,这里为了测试比对数据,通过@GroupThreads分配了读4个线程,写1个线程。

JMH中的一些陷阱

Dead-Code代码

编写JMH用例时需要考虑虚拟机的优化,避免性能测试结果不准。下例由于measureWrong并没有返回值,所以虚拟机会优化掉这个方法。

代码语言:javascript
AI代码解释
复制
...省略头信息
public class JMHSample_08_DeadCode {
    private double x = Math.PI;

    @Benchmark
    public void baseline() {
        //基准线,什么都不做
    }

    @Benchmark
    public void measureWrong() {
        //错误:结果未被使用,整个方法被优化掉了
        Math.log(x);
    }

    @Benchmark
    public double measureRight() {
        //正确:结果被使用
        return Math.log(x);
    }
    ...省略运行信息
}
代码语言:javascript
AI代码解释
复制
Benchmark                            Mode  Cnt  Score   Error   Units
JMHSample_08_DeadCode.baseline      thrpt    3  4.188 ± 0.840  ops/ns
JMHSample_08_DeadCode.measureRight  thrpt    3  0.060 ± 0.012  ops/ns
JMHSample_08_DeadCode.measureWrong  thrpt    3  3.405 ± 1.065  ops/ns
黑洞

使用Blackholes来避免JIT忽略未被使用的信息。

代码语言:javascript
AI代码解释
复制
...省略头信息
public class JMHSample_09_Blackholes {
    double x1 = Math.PI;
    double x2 = Math.PI * 2;

    /*
     * 基准
     */
    @Benchmark
    public double baseline() {
        return Math.log(x1);
    }

    /*
     * Math.log(x2)正常,Math.log(x1)被优化掉
     */

    @Benchmark
    public double measureWrong() {
        Math.log(x1);
        return Math.log(x2);
    }

    @Benchmark
    public double measureRight_1() {
        return Math.log(x1) + Math.log(x2);
    }

    /*
     * 使用Blackhole对象将值存储这里,避免被优化掉
     */
    @Benchmark
    public void measureRight_2(Blackhole bh) {
        bh.consume(Math.log(x1));
        bh.consume(Math.log(x2));
    }
    ...省略运行信息
}
代码语言:javascript
AI代码解释
复制
Benchmark                                Mode  Cnt  Score   Error   Units
JMHSample_09_Blackholes.baseline        thrpt    3  0.058 ± 0.026  ops/ns
JMHSample_09_Blackholes.measureRight_1  thrpt    3  0.028 ± 0.050  ops/ns
JMHSample_09_Blackholes.measureRight_2  thrpt    3  0.026 ± 0.018  ops/ns
JMHSample_09_Blackholes.measureWrong    thrpt    3  0.055 ± 0.024  ops/ns
常量折叠

JIT认为被测试方法总是返回常量,从而在优化时直接返回常量给调用者而不再调用方法。

代码语言:javascript
AI代码解释
复制
...省略头信息
public class JMHSample_10_ConstantFold {
    private double x = Math.PI;

    private final double wrongX = Math.PI;

    @Benchmark
    public double baseline() {
        // 基准线
        return Math.PI;
    }

    @Benchmark
    public double measureWrong_1() {
        //错误:源是可预见的,计算是可折叠的
        return Math.log(Math.PI);
    }

    @Benchmark
    public double measureWrong_2() {
        //错误:源是可预见的,计算是可折叠的
        return Math.log(wrongX);
    }

    @Benchmark
    public double measureRight() {
        //正确,源是不可预见的
        return Math.log(x);
    }
    ...省略运行信息
}
代码语言:javascript
AI代码解释
复制
Benchmark                                  Mode  Cnt  Score   Error   Units
JMHSample_10_ConstantFold.baseline        thrpt    3  0.537 ± 1.565  ops/ns
JMHSample_10_ConstantFold.measureRight    thrpt    3  0.060 ± 0.019  ops/ns
JMHSample_10_ConstantFold.measureWrong_1  thrpt    3  0.422 ± 1.372  ops/ns
JMHSample_10_ConstantFold.measureWrong_2  thrpt    3  0.406 ± 1.132  ops/ns
避免循环

JMH不建议使用循环,因为JIT会种循环做优化,以消除循环调用成本。

代码语言:javascript
AI代码解释
复制
...省略头信息
public class JMHSample_11_Loops {
    int x = 1;
    int y = 2;

    @Benchmark
    public int measureRight() {
        return (x + y);
    }

    private int reps(int reps) {
        int s = 0;
        for (int i = 0; i < reps; i++) {
            s += (x + y);
        }
        return s;
    }

    @Benchmark
    @OperationsPerInvocation(1)
    public int measureWrong_1() {
        return reps(1);
    }

    @Benchmark
    @OperationsPerInvocation(10)
    public int measureWrong_10() {
        return reps(10);
    }

    @Benchmark
    @OperationsPerInvocation(100)
    public int measureWrong_100() {
        return reps(100);
    }

    @Benchmark
    @OperationsPerInvocation(1_000)
    public int measureWrong_1000() {
        return reps(1_000);
    }

    @Benchmark
    @OperationsPerInvocation(10_000)
    public int measureWrong_10000() {
        return reps(10_000);
    }

    @Benchmark
    @OperationsPerInvocation(100_000)
    public int measureWrong_100000() {
        return reps(100_000);
    }
    ...省略运行信息
}

上例中,@OperationsPerInvocation为每次Benchmark调用的操作数,其告诉JMH统计性能的时候需要做修正,比如@OperationsPerInvocation(10)调用10次。

代码语言:javascript
AI代码解释
复制
Benchmark                                Mode  Cnt   Score     Error   Units
JMHSample_11_Loops.measureRight         thrpt    3   0.439 ±   0.447  ops/ns
JMHSample_11_Loops.measureWrong_1       thrpt    3   0.392 ±   0.757  ops/ns
JMHSample_11_Loops.measureWrong_10      thrpt    3   3.755 ±   3.118  ops/ns
JMHSample_11_Loops.measureWrong_100     thrpt    3  30.362 ±  63.189  ops/ns
JMHSample_11_Loops.measureWrong_1000    thrpt    3  34.975 ± 161.861  ops/ns
JMHSample_11_Loops.measureWrong_10000   thrpt    3  51.644 ±  18.460  ops/ns
JMHSample_11_Loops.measureWrong_100000  thrpt    3  56.236 ±  13.568  ops/ns
分叉

默认情况下,JMH是分叉测试的。

代码语言:javascript
AI代码解释
复制
...省略头信息
public class JMHSample_12_Forking {
    public interface Counter {
        int inc();
    }

    public static class Counter1 implements Counter {
        private int x;

        @Override
        public int inc() {
            return x++;
        }
    }

    public static class Counter2 implements Counter {
        private int x;

        @Override
        public int inc() {
            return x++;
        }
    }

    /**
     * And this is how we measure it.
     * Note this is susceptible for same issue with loops we mention in previous examples.
     */

    public int measure(Counter c) {
        int s = 0;
        for (int i = 0; i < 10; i++) {
            s += c.inc();
        }
        return s;
    }

    Counter c1 = new Counter1();
    Counter c2 = new Counter2();

    //首先单独测量Counter1
    //Fork(0)帮助在同一JVM中运行
    @Benchmark
    @Fork(0)
    public int measure_1_c1() {
        return measure(c1);
    }

    //单独Counter2
    @Benchmark
    @Fork(0)
    public int measure_2_c2() {
        return measure(c2);
    }

    //单独Counter1
    @Benchmark
    @Fork(0)
    public int measure_3_c1_again() {
        return measure(c1);
    }

    /*
     * 下面两个是带有@Fork注解。
     * JMH将此注解作为在forked JVM中运行测试的请求,通过命令选项“-f”强制对所有测试执行此行为更简单。
     * forking是默认的,但我们仍使用注释来保持一致性。
     */
    @Benchmark
    @Fork(1)
    public int measure_4_forked_c1() {
        return measure(c1);
    }

    @Benchmark
    @Fork(1)
    public int measure_5_forked_c2() {
        return measure(c2);
    }

    /*
     * 结果可看到fork(0)的方法会越来越慢,因为它们是在同一JVM中运行,相互影响。
     * c1,c2,c1_again 的实现相同,跑分却不同,因为运行在同一个 JVM 中;而 forked_c1 和 forked_c2 则表现出了一致的性能。
     */
    ...省略运行信息
}
代码语言:javascript
AI代码解释
复制
Benchmark                                  Mode  Cnt  Score   Error   Units
JMHSample_12_Forking.measure_1_c1         thrpt    3  0.508 ± 0.298  ops/ns
JMHSample_12_Forking.measure_2_c2         thrpt    3  0.052 ± 0.199  ops/ns
JMHSample_12_Forking.measure_3_c1_again   thrpt    3  0.075 ± 0.072  ops/ns
JMHSample_12_Forking.measure_4_forked_c1  thrpt    3  0.350 ± 0.521  ops/ns
JMHSample_12_Forking.measure_5_forked_c2  thrpt    3  0.346 ± 0.502  ops/ns

JMH基本介绍到这里就结束了。如果大家需要更多的入门实例,可参照官方地址:

代码语言:javascript
AI代码解释
复制
http://hg.openjdk.java.net/code-tools/jmh/file/
https://github.com/openjdk/jmh/tree/master/jmh-samples

可视化

JMH的可视化非常简单,只需要在运行时导出为json格式的报告,然后再利用可视化工具分析即可,具体如下:

代码语言:javascript
AI代码解释
复制
public static void main(String[] args) throws RunnerException {
    Options opt = new OptionsBuilder()
            .include(JMHSample_09_Blackholes.class.getSimpleName())
            
            .result("result.json")
            .resultFormat(ResultFormatType.JSON)
            
            .build();
    new Runner(opt).run();
}

运行后,项目下会生成一个result.json的结果报告。 目前JMH的在线可视化主要有如下两款工具,将json结果报告导入即可:

代码语言:javascript
AI代码解释
复制
https://jmh.morethan.io/
http://deepoove.com/jmh-visual-chart/

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

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

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

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
JMH使用指南[通俗易懂]
关于JMH,可以直接查看官网地址http://openjdk.java.net/projects/code-tools/jmh/
全栈程序员站长
2022/09/08
2.2K0
顶级Java才懂的,基准测试JMH!
最近在手写一个ID生成器,需要比较UUID和目前比较流行的 NanoID之间的速度差异,当然也要测一下根据规则自创的ID生成器。
xjjdog
2021/11/19
9390
架构师Java 并发基准测试神器的-JMH,程序员必看!
在Java编程这个行业里面性能测试这个话题非常庞大,我们可以从网络聊到操作系统,再从操作系统聊到内核,再从内核聊到你怀疑人生有木有。
Java架构师进阶技术
2020/01/31
9930
架构师Java 并发基准测试神器的-JMH,程序员必看!
JMH使用说明「建议收藏」
JMH,即Java Microbenchmark Harness,是专门用于代码微基准测试的工具套件。何谓Micro Benchmark呢?简单的来说就是基于方法层面的基准测试,精度可以达到微秒级。当你定位到热点方法,希望进一步优化方法性能的时候,就可以使用JMH对优化的结果进行量化的分析。和其他竞品相比——如果有的话,JMH最有特色的地方就是,它是由Oracle内部实现JIT的那拨人开发的,对于JIT以及JVM所谓的“profile guided optimization”对基准测试准确性的影响可谓心知肚明(smile)
全栈程序员站长
2022/09/08
1.4K0
JMH使用说明「建议收藏」
不要再用main方法测试代码性能了,用这款JDK自带工具
作为软件开发人员,我们通常会写一些测试程序用来对比不同算法、不同工具的性能问题。而最常见的做法是写一个main方法,构造模拟场景进行并发测试。
程序新视界
2021/01/13
5420
JAVA拾遗 — JMH与8个代码陷阱
JMH (http://openjdk.java.net/projects/code-tools/jmh/) 是 Java Microbenchmark Harness(微基准测试)框架的缩写(2013年首次发布)。与其他众多测试框架相比,其特色优势在于它是由 Oracle 实现 JIT 的相同人员开发的。在此,我想特别提一下 Aleksey Shipilev (http://shipilev.net/)(JMH 的作者兼布道者)和他优秀的博客文章。笔者花费了一个周末,将 Aleksey 大神的博客,特别是那些和 JMH 相关的文章通读了一遍,外加一部公开课视频 《"The Lesser of Two Evils" Story》 ,将自己的收获归纳在这篇文章中,文中不少图片都来自 Aleksey 公开课视频。
kirito-moe
2018/09/30
1.7K1
JAVA拾遗 — JMH与8个代码陷阱
JMH - Java 代码性能测试的终极利器、必须掌握
现在的 JVM 已经越来越为智能,它可以在编译阶段、加载阶段、运行阶段对代码进行优化。比如你写了一段不怎么聪明的代码,到了 JVM 这里,它发现几处可以优化的地方,就顺手帮你优化了一把。这对程序的运行固然美妙,却让开发者不能准确了解程序的运行情况。在需要进行性能测试时,如果不知道 JVM 优化细节,可能会导致你的测试结果差之毫厘,失之千里,同样的,Java 诞生之初就有一次编译、随处运行的口号,JVM 提供了底层支持,也提供了内存管理机制,这些机制都会对我们的性能测试结果造成不可预测的影响。
未读代码
2020/08/25
5.9K0
别再写 main 方法测试了,太 Low!这才是专业 Java 测试方法!
点击上方“芋道源码”,选择“设为星标” 管她前浪,还是后浪? 能浪的浪,才是好浪! 每天 10:33 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | Java 2021 超神之路,很肝~ 中文详细注释的开源项目 RPC 框架 Dubbo 源码解析 网络应用框架 Netty 源码解析 消息中间件 RocketMQ 源码解析 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析 作业调度中间件 Elastic-Job 源码解析 分布式事务中间件 TCC-Transaction
芋道源码
2022/03/04
3090
Java性能测试利器:JMH入门与实践|得物技术
在软件开发中,性能测试是不可或缺的一环。但是编写基准测试来正确衡量大型应用程序的一小部分的性能却又非常困难。当基准测试单独执行组件时,JVM或底层硬件可能会对您的组件应用许多优化。当组件作为大型应用程序的一部分运行时,这些优化可能无法应用。因此,实施不当的微基准测试可能会让您相信组件的性能比实际情况更好。编写正确的Java微基准测试通常需要防止JVM和硬件在微基准测试执行期间应用的优化,而这些优化在实际生产系统中是无法应用的。这就是JMH(Java 微基准测试工具)可以帮助您实现的功能。这篇文章我会全面给大家介绍下JMH的各个方面。
得物技术
2024/11/21
4130
在java中使用JMH(Java Microbenchmark Harness)做性能测试
在java中使用JMH(Java Microbenchmark Harness)做性能测试
程序那些事
2020/07/08
1.1K0
性能调优必备利器之 JMH
if 快还是 switch 快?HashMap 的初始化 size 要不要指定,指定之后性能可以提高多少?各种序列化方法哪个耗时更短?
用户4172423
2020/06/12
6140
Java Microbenchmark Harness-Java快速入门教程
这篇快速文章重点介绍 JMH(Java Microbenchmark Harness)。首先,我们熟悉 API 并了解其基础知识。然后,我们将看到在编写微基准测试时应该考虑的一些最佳实践。
jack.yang
2025/04/05
1540
别只会 main 方法做测试,太 Low!这才是专业 Java 测试方法!
前言 “"If you cannot measure it, you cannot improve it". 在日常开发中,我们对一些代码的调用或者工具的使用会存在多种选择方式,在不确定他们性能的时候,我们首先想要做的就是去测量它。大多数时候,我们会简单的采用多次计数的方式来测量,来看这个方法的总耗时。 但是,如果熟悉JVM类加载机制的话,应该知道JVM默认的执行模式是JIT编译与解释混合执行。JVM通过热点代码统计分析,识别高频方法的调用、循环体、公共模块等,基于JIT动态编译技术,会将热点代码转换成机
java思维导图
2022/03/21
3740
从一个诡异的问题看JVM动态反优化
前一段时间在做代码性能比较的时候用到了jmh这个工具,原本以为拥有了这个方便的工具就能hold住java微基准测试这个命题。但是事实上,用着用着就发现自己的理解还非常不深入,有很多在测试的时候难以解释的现象。于是查阅了相关资料,才发现这里面的水比我想象要深,趁着记忆还热乎,赶紧记录一下。
mythsman
2022/11/14
2920
别再写 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
4550
JMH简介
  JMH是新的microbenchmark(微基准测试)框架(2013年首次发布)。与其他众多框架相比它的特色优势在于,它是由Oracle实现JIT的相同人员开发的。特别是我想提一下Aleksey Shipilev和他优秀的博客文章。JMH可能与最新的Oracle JRE同步,其结果可信度很高。
全栈程序员站长
2022/09/14
2K0
微基准测试框架JMH
最典型的场景就是你想知道两个功能相同的操作到底哪个性能比较好,通常会自己手撸一段代码,前后增加时间,然后对比多次执行的时间。这种做法比较原始,还要自己处理预热等问题。JMH提供了比较丰富的操作。且看如何使用。
李鸿坤
2020/07/17
6440
使用 JMH 做 Kotlin 的基准测试一. 基准测试二. JMH三. 举例总结
基准测试是一种测量和评估软件性能指标的活动。你可以在某个时候通过基准测试建立一个已知的性能水平(称为基准线),当系统的软硬件环境发生变化之后再进行一次基准测试以确定那些变化对性能的影响。
fengzhizi715
2018/12/26
1.7K1
基准测试工具JMH
Java Microbenchmark Harness,简称JMH,由OpenJDK开发,用来构建、运行和分析Java或其他JVM语言代码的微基准测试框架。适合于方法级别的细粒度测试,并不适用于系统之间的链路测试。
johnny666
2024/09/28
2590
Java微基准测试神器JMH初探
当我们编写一段Java代码之后,如果想知道代码性能如何,就需要进行一些快速的性能测试。
FunTester
2023/08/04
3110
Java微基准测试神器JMH初探
相关推荐
JMH使用指南[通俗易懂]
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档