Java 并发测试神器:基准测试神器-JMH

旧版Linux安装新NVIDIA显卡“No devices were found”排查实战 在Linux系统里安装NVIDIA闭源驱动,本质是加载内核模块并让它在PCIe总线上匹配设备ID。当遇到“No devices were found”这类提示,很多人误以为显卡损坏,其实问题常出在驱动层与硬件间的兼容链路。新架构显卡(如RTX 5090)对内核版本、BAR窗口、nouveau冲突等都有更高要求,而老发行版(如麒麟V10)的内核相对保守,nvidia-smi自然无法识别设备。本文从基础概念出发,讲解如何用lspci、lsmod、dmesg定位问题层级,系统梳理禁用nouveau、升级内核与工具 阅读详情

点击上方“芋道源码”,选择“设为星标”

做积极的人,而不是积极废人!

源码精品专栏

 

来源:吕彦峰 sq.163yun.com/blog/article/179671960481783808

性能测试这个话题非常庞大,我们可以从网络聊到操作系统,再从操作系统聊到内核,再从内核聊到你怀疑人生有木有。

先拍几个砖出来吧,我在写代码的时候经常有这种怀疑:写法A快还是写法B快,某个位置是用ArrayList还是LinkedList,HashMap还是TreeMap,HashMap的初始化size要不要指定,指定之后究竟比默认的DEFAULT_SIZE性能好多少。。。

如果你还是通过for循环或者手撸method来测试你的内容的话,那么JMH就是你必须要明白的内容了,因为已经有人把基准测试的轮子造好了,接下来我们就一起看看这个轮子怎么用:

JMH只适合细粒度的方法测试,并不适用于系统之间的链路测试!
JMH只适合细粒度的方法测试,并不适用于系统之间的链路测试!
JMH只适合细粒度的方法测试,并不适用于系统之间的链路测试!

JMH入门:

JMH是一个工具包,如果我们要通过JMH进行基准测试的话,直接在我们的pom文件中引入JMH的依赖即可:

        <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>

通过一个HelloWorld程序来看一下JMH如果工作:

@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
public class JMHSample_01_HelloWorld {

    static class Demo {
        int id;
        String name;
        public Demo(int id, String name) {
            this.id = id;
            this.name = name;
        }
    }

    static List<Demo> demoList;
    static {
        demoList = new ArrayList();
        for (int i = 0; i < 10000; i ++) {
            demoList.add(new Demo(i, "test"));
        }
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void testHashMapWithoutSize() {
        Map map = new HashMap();
        for (Demo demo : demoList) {
            map.put(demo.id, demo.name);
        }
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void testHashMap() {
        Map map = new HashMap((int)(demoList.size() / 0.75f) + 1);
        for (Demo demo : demoList) {
            map.put(demo.id, demo.name);
        }
    }

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

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

======================================执行结果======================================
Benchmark                                       Mode  Cnt    Score     Error  Units
JMHSample_01_HelloWorld.testHashMap             avgt    5  147.865 ±  81.128  us/op
JMHSample_01_HelloWorld.testHashMapWithoutSize  avgt    5  224.897 ± 102.342  us/op
======================================执行结果======================================

上面的代码用中文翻译一下:分别定义两个基准测试的方法testHashMapWithoutSize和 testHashMap,这两个基准测试方法执行流程是:每个方法执行前都进行5次预热执行,每隔1秒进行一次预热操作,预热执行结束之后进行5次实际测量执行,每隔1秒进行一次实际执行,我们此次基准测试测量的是平均响应时长,单位是us。

预热?为什么要预热?因为 JVM 的 JIT 机制的存在,如果某个函数被调用多次之后,JVM 会尝试将其编译成为机器码从而提高执行速度。为了让 benchmark 的结果更加接近真实情况就需要进行预热。

从上面的执行结果我们看出,针对一个Map的初始化参数的给定其实有很大影响,当我们给定了初始化参数执行执行的速度是没给定参数的2/3,这个优化速度还是比较明显的,所以以后大家在初始化Map的时候能给定参数最好都给定了,代码是处处优化的,积少成多。

通过上面的内容我们已经基本可以看出来JMH的写法雏形了,后面的介绍主要是一些注解的使用:

@Benchmark

@Benchmark标签是用来标记测试方法的,只有被这个注解标记的话,该方法才会参与基准测试,但是有一个基本的原则就是被@Benchmark标记的方法必须是public的。

@Warmup

@Warmup用来配置预热的内容,可用于类或者方法上,越靠近执行方法的地方越准确。一般配置warmup的参数有这些:

  • iterations:预热的次数。

  • time:每次预热的时间。

  • timeUnit:时间单位,默认是s。

  • batchSize:批处理大小,每次操作调用几次方法。(后面用到)

@Measurement

用来控制实际执行的内容,配置的选项本warmup一样。

@BenchmarkMode

@BenchmarkMode主要是表示测量的纬度,有以下这些纬度可供选择:

  • Mode.Throughput 吞吐量纬度

  • Mode.AverageTime 平均时间

  • Mode.SampleTime 抽样检测

  • Mode.SingleShotTime 检测一次调用

  • Mode.All 运用所有的检测模式 在方法级别指定@BenchmarkMode的时候可以一定指定多个纬度,例如:@BenchmarkMode({Mode.Throughput, Mode.AverageTime, Mode.SampleTime, Mode.SingleShotTime}),代表同时在多个纬度对目标方法进行测量。

@OutputTimeUnit

@OutputTimeUnit代表测量的单位,比如秒级别,毫秒级别,微妙级别等等。一般都使用微妙和毫秒级别的稍微多一点。该注解可以用在方法级别和类级别,当用在类级别的时候会被更加精确的方法级别的注解覆盖,原则就是离目标更近的注解更容易生效。

@State

在很多时候我们需要维护一些状态内容,比如在多线程的时候我们会维护一个共享的状态,这个状态值可能会在每隔线程中都一样,也有可能是每个线程都有自己的状态,JMH为我们提供了状态的支持。该注解只能用来标注在类上,因为类作为一个属性的载体。@State的状态值主要有以下几种:

  • Scope.Benchmark 该状态的意思是会在所有的Benchmark的工作线程中共享变量内容。

  • Scope.Group 同一个Group的线程可以享有同样的变量

  • Scope.Thread 每隔线程都享有一份变量的副本,线程之间对于变量的修改不会相互影响。下面看两个常见的@State的写法:

1.直接在内部类中使用@State作为“PropertyHolder”

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 measureUnshared(ThreadState state) {
        state.x++;
    }

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

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

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

2.在Main类中直接使用@State作为注解,是Main类直接成为“PropertyHolder”
@State(Scope.Thread)
public class JMHSample_04_DefaultState {
    double x = Math.PI;

    @Benchmark
    public void measure() {
        x++;
    }

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

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

我们试想以下@State的含义,它主要是方便框架来控制变量的过程逻辑,通过@State标示的类都被用作属性的容器,然后框架可以通过自己的控制来配置不同级别的隔离情况。被@Benchmark标注的方法可以有参数,但是参数必须是被@State注解的,就是为了要控制参数的隔离。

但是有些情况下我们需要对参数进行一些初始化或者释放的操作,就像Spring提供的一些init和destory方法一样,JHM也提供有这样的钩子:

  • @Setup 必须标示在@State注解的类内部,表示初始化操作

  • @TearDown 必须表示在@State注解的类内部,表示销毁操作

初始化和销毁的动作都只会执行一次。

@State(Scope.Thread)
public class JMHSample_05_StateFixtures {
    double x;

    @Setup
    public void prepare() {
        x = Math.PI;
    }

    @TearDown
    public void check() {
        assert x > Math.PI : "Nothing changed?";
    }

    @Benchmark
    public void measureRight() {
        x++;
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JMHSample_05_StateFixtures.class.getSimpleName())
                .forks(1)
                .jvmArgs("-ea")
                .build();

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

虽然我们可以执行初始化和销毁的动作,但是总是感觉还缺点啥?对,就是初始化的粒度。因为基准测试往往会执行多次,那么能不能保证每次执行方法的时候都初始化一次变量呢?@Setup和@TearDown提供了以下三种纬度的控制:

  • Level.Trial 只会在个基础测试的前后执行。包括Warmup和Measurement阶段,一共只会执行一次。

  • Level.Iteration 每次执行记住测试方法的时候都会执行,如果Warmup和Measurement都配置了2次执行的话,那么@Setup和@TearDown配置的方法的执行次数就4次。

  • Level.Invocation 每个方法执行的前后执行(一般不推荐这么用)

@Param

在很多情况下,我们需要测试不同的参数的不同结果,但是测试的了逻辑又都是一样的,因此如果我们编写镀铬benchmark的话会造成逻辑的冗余,幸好JMH提供了@Param参数来帮助我们处理这个事情,被@Param注解标示的参数组会一次被benchmark消费到。

@State(Scope.Benchmark)
public class ParamTest {

    @Param({"1", "2", "3"})
    int testNum;

    @Benchmark
    public String test() {
        return String.valueOf(testNum);
    }

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

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

测试线程的数量,可以配置在方法或者类上,代表执行测试的线程数量。

通常看到这里我们会比较迷惑Iteration和Invocation区别,我们在配置Warmup的时候默认的时间是的1s,即1s的执行作为一个Iteration,假设每次方法的执行是100ms的话,那么1个Iteration就代表10个Invocation。

JMH进阶

通过以上的内容我们已经基本可以掌握JMH的使用了,下面就主要介绍一下JMH提供的一些高级特性了。

不要编写无用代码

因为现代的编译器非常聪明,如果我们在代码使用了没有用处的变量的话,就容易被编译器优化掉,这就会导致实际的测量结果可能不准确,因为我们要在测量的方法中避免使用void方法,然后记得在测量的结束位置返回结果。这么做的目的很明确,就是为了与编译器斗智斗勇,让编译器不要改变这段代码执行的初衷。

Blackhole介绍

Blackhole会消费传进来的值,不提供任何信息来确定这些值是否在之后被实际使用。Blackhole处理的事情主要有以下几种:

  • 死代码消除:入参应该在每次都被用到,因此编译器就不会把这些参数优化为常量或者在计算的过程中对他们进行其他优化。

  • 处理内存壁:我们需要尽可能减少写的量,因为它会干扰缓存,污染写缓冲区等。这很可能导致过早地撞到内存壁

我们在上面说到需要消除无用代码,那么其中一种方式就是通过Blackhole,我们可以用Blackhole来消费这些返回的结果。

1:返回测试结果,防止编译器优化
@Benchmark
public double measureRight_1() {
    return Math.log(x1) + Math.log(x2);
}

2.通过Blackhole消费中间结果,防止编译器优化
@Benchmark
public void measureRight_2(Blackhole bh) {
    bh.consume(Math.log(x1));
    bh.consume(Math.log(x2));
}
循环处理

我们虽然可以在Benchmark中定义循环逻辑,但是这么做其实是不合适的,因为编译器可能会将我们的循环进行展开或者做一些其他方面的循环优化,所以JHM建议我们不要在Beanchmark中使用循环,如果我们需要处理循环逻辑了,可以结合@BenchmarkMode(Mode.SingleShotTime)和@Measurement(batchSize = N)来达到同样的效果.

@State(Scope.Thread)
public class JMHSample_26_BatchSize {

    List<String> list = new LinkedList<>();

    // 每个iteration中做5000次Invocation
    @Benchmark
    @Warmup(iterations = 5, batchSize = 5000)
    @Measurement(iterations = 5, batchSize = 5000)
    @BenchmarkMode(Mode.SingleShotTime)
    public List<String> measureRight() {
        list.add(list.size() / 2, "something");
        return list;
    }

    @Setup(Level.Iteration)
    public void setup(){
        list.clear();
    }

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

        new Runner(opt).run();
    }

}
方法内联

方法内联:如果JVM监测到一些小方法被频繁的执行,它会把方法的调用替换成方法体本身。比如说下面这个:

    private int add4(int x1, int x2, int x3, int x4) {
        return add2(x1, x2) + add2(x3, x4);
    }

    private int add2(int x1, int x2) {
        return x1 + x2;
    }

运行一段时间后JVM会把add2方法去掉,并把你的代码翻译成:

    private int add4(int x1, int x2, int x3, int x4) {
        return x1 + x2 + x3 + x4;
    }

JMH提供了CompilerControl注解来控制方法内联,但是实际上我感觉比较有用的就是两个了:

  • CompilerControl.Mode.DONT_INLINE:强制限制不能使用内联

  • CompilerControl.Mode.INLINE:强制使用内联 看一下官方提供的例子把:

@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class JMHSample_16_CompilerControl {

    public void target_blank() {

    }

    @CompilerControl(CompilerControl.Mode.DONT_INLINE)
    public void target_dontInline() {

    }

    @CompilerControl(CompilerControl.Mode.INLINE)
    public void target_inline() {

    }

    @Benchmark
    public void baseline() {

    }

    @Benchmark
    public void dontinline() {
        target_dontInline();
    }

    @Benchmark
    public void inline() {
        target_inline();
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JMHSample_16_CompilerControl.class.getSimpleName())
                .warmupIterations(0)
                .measurementIterations(3)
                .forks(1)
                .build();

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

======================================执行结果==============================
Benchmark                                Mode  Cnt  Score   Error  Units
JMHSample_16_CompilerControl.baseline    avgt    3  0.896 ± 3.426  ns/op
JMHSample_16_CompilerControl.dontinline  avgt    3  0.344 ± 0.126  ns/op
JMHSample_16_CompilerControl.inline      avgt    3  0.391 ± 2.622  ns/op
======================================执行结果==============================


欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:

已在知识星球更新源码解析如下:


最近更新《芋道 SpringBoot 2.X 入门》系列,已经 20 余篇,覆盖了 MyBatis、Redis、MongoDB、Elasticsearch、分库分表、读写分离、SpringMVC、SpringWebflux、WebSocket、性能测试等等内容。

提供近 2W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

如果你喜欢这篇文章,喜欢,转发。

生活很美好,明天见(。・ω・。)ノ♡

已解决“TimeouEror [WinEror 10060由于连接方在一段时间后没有正确答复 或连接的主机没有反应,连接尝试失败“,亲测有效!!! 已解决"TimeouEror [WinEror 10060由于连接方在一段时间后没有正确答复 或连接的主机没有反应,连接尝试失败",亲测有效!!! 阅读详情

相关推荐

从‘最长白列’到‘八邻域’:智能车图像巡线算法怎么选?我的踩坑经验分享

本文深入探讨了全国大学生智能汽车竞赛中图像巡线算法的选型与优化,对比了最长白列法、八邻域算法等五种主流方法的性能与适用场景。通过实战数据和代码示例,分析了各算法在直道、弯道及特殊赛道元素中的表现,并提供了内存优化、参数调整等实用技巧,帮助参赛团队提升智能车的巡线精度与效率。

weixin_30374009的博客 642

使用JMH做Benchmark基准测试

目录 BenchMark介绍 开始前的步骤 例子 代码 报告 注解介绍 @BenchmarkMode @OutputTimeUnit @Iteration @WarmUp ...

weixin_30478757的博客 604

Keil MDK编译错误#541解决方案与ARM_Compiler包解析

在嵌入式开发中,编译器工具链的依赖管理是确保项目顺利构建的关键环节。以Keil MDK为例,其软件包依赖机制通过组件化设计实现功能解耦,其中ARM_Compiler包专门处理系统IO重定向等编译器扩展功能。这种架构既提升了模块复用性,也带来了版本兼容性挑战。当出现'Error #541: component missing'报错时,通常是由于中间件组件(如文件系统)在新版本中显式依赖了ARM_Compiler包。开发者需要通过Pack Installer安装该包,并在Run-Time Environment

weixin_32129187的博客 371

【进阶之路】Java代码性能调优-基准测试工具JMH(三)

导言 大家好,我是南橘,从接触java到现在也有差不多两年时间了,两年时间,从一名连java有几种数据结构都不懂超级小白,到现在懂了一点点的进阶小白,学到了不少的东西。知识越分享越值钱,我这段时间总结(包括从别的大佬那边学习,引用)了一些平常学习和面试中的重点(自我认为),希望给大家带来一些帮助 第一件事还是把思维导图贴给大家,因为用的是免费版,所以有水印,如果需要原始版本的话,可以加我的微信: 【进阶之路】Java代码性能调优(一) 【进阶之路】Java代码性能调优(二) 前两章介绍了JA

南橘Home 743

华为硬件工程师笔试题

1、基尔霍夫定理的内容是什么?(仕兰微电子)   基尔霍夫定理包括电流定律和电压定律。   电流定律(KCL):在集总电路中,任何时刻,对任一结点,所有流出结点的支路电流的代数和恒等于零。   电压定律(KVL):在集总电路中,任何时刻,沿任一回路,所有支路电压的代数和恒等于零。   2、平板电容公式(C=εS/4πkd)。(未知)   3、最基本的如三极管曲线特性。(未知)   4、描述反馈电路...

weixin_33717117的博客 2万+

Jetson Nano 【1】入手开箱、烧系统

类似于半开箱哈哈 怀着小期待的心情,屁颠屁颠跑到村口领快递,拿到了这个香喷喷的Jetson Nano 开发板 开箱: 由于太激动了忘记拍点啥,于是在最后留了张全家福 板子的结构: 我觉得这个有必要记录一下,于是去官方文档拿了张图来:官方文档传送 1=SD card 的卡槽,位于第二层板子的背部,也就是大风扇屁股位置 2=40针扩展接头(还没开用) 3=USB的供电口,根据大佬测试(某哩...

椰子奶糖的博客 4198

顶级Java才懂的,基准测试JMH!

原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。最近在手写一个ID生成器,需要比较UUID和目前比较流行的 NanoID之间的速度差异,当然也要测一下根据规则自...

小姐姐味道 1287

STC32G电调调试血泪史:从TPH1R403NL MOS管烧毁到PWM信号异常排查全记录

本文详细记录了STC32G无刷电调调试过程中的常见问题与解决方案,包括MOS管烧毁、PWM信号异常等关键故障排查。通过电源系统检测、驱动电路验证及三相平衡调试等实战经验,帮助硬件爱好者快速定位问题,提升电调调试效率。特别针对TPH1R403NL等MOS管的保护措施进行了重点分析。

weixin_33736048的博客 551

橘子学JDK之JMH-02(BenchmarkModes)

没啥总结的就是那两个注解,很详细了。

liuwenqiang1314的博客 1528

中心对数比变换(Centered Log Ratio Transformation,CLR)的原理及scikit-bio介绍

中心对数比变换(Centered Log Ratio Transformation,CLR)是一种数据预处理方法,常用于成分数据分析领域。在成分数据中,各成分之间通常存在一定的约束关系,比如它们的和为固定值等,中心对数比变换可以有效地处理这种具有特殊约束的数据。官方文档scikit-bio是一个在Python3中处理生物数据的库成分统计 (skbio.stats.composition )模块中的,此函数将组合从Aitchison几何体转换到真实空间。这个clr。

RECORD LEARN PROGRESS 1万+

基于深度确定性策略梯度的永磁同步电机强化学习控制方法

本文提出了一种基于深度确定性策略梯度(DDPG)的永磁同步电机(PMSM)电流内环智能控制方法。首先建立了PMSM在d-q坐标系下的数学模型,分析了传统矢量控制双闭环系统中PI控制器的局限性。针对电流内环控制问题,设计了包含电流跟踪误差、转速信息和历史控制量的状态空间,将电压输出作为动作空间,并构建了兼顾跟踪精度和响应速度的奖励函数。通过DDPG算法训练智能体,使其能够自适应调整控制策略。仿真结果表明,与固定参数的PI控制器相比,DDPG控制器在动态响应速度和抗干扰能力方面具有明显优势,为PMSM高性能控制

huanghm88的专栏 104

基准测试神器 - JMH [ Java Microbenchmark Harness ]

一. 简介 JMH,全称 Java Microbenchmark Harness (微基准测试框架),是专门用于Java代码微基准测试的一套测试工具API,是由 OpenJDK/Oracle官方发布的工具。其精度可以达到毫秒级.可以执行一个函数需要多少时间,或者一个算法有多种不同实现等情况下,选择一个性能最好的那个. Java的基准测试需要注意的几个点: 测试前需要预热...

张伯毅的专栏 4218

AI:270-基于ASFF改进YOLOv8检测头的多尺度特征融合方法详解与实战

ASFF是一种基于自适应特征融合的策略,能够动态调整不同尺度特征的融合权重,适应场景中不同大小的目标。传统的YOLOv8检测头使用固定的特征融合策略,而ASFF则通过引入学习参数,使得网络能够根据输入图像的特征自适应地选择不同尺度特征的重要性。这一策略对于检测小目标或尺度变化大的目标具有显著优势。本文提出了一种改进YOLOv8检测头的新方法,通过引入自适应空间特征融合模块(ASFF),有效提升了多尺度目标检测的性能,特别是在小目标检测任务中的表现。

一键难忘的博客 3915

Java 并发性能测试 JMH 框架编写基准测试用例实战

Elasticsearch 与 Java 客户端集成 High Level REST Client 实战

yA00TJ6EL的博客 747

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

基准测试神器JMH——详解36个官方例子

本文已收录 https://github.com/lkxiaolou/lkxiaolou 欢迎star。 简介 基准测试是指通过设计科学的测试方法、测试工具和测试系统,实现对一类测试对象的某项性能指标进行定量的和可对比的测试。 而JMH是一个用来构建,运行,分析Java或其他运行在JVM之上的语言的 纳秒/微秒/毫秒/宏观 级别基准测试的工具。 JMH is a Java harness for building, running, and analysing nano/micro/milli/mac.

捉虫大师 1734

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

JMH基准测试

开发小工具-JMH基准测试 我们在写代码的时候经常有这种怀疑:写法A快还是写法B快?哪个写法性能更好,效率更高。 在开发过程中常常需要对方法性能做测定,JMH是一个轻量级压测框架,适合开发简单做方法性能的测试。 JMH和jMeter的使用场景还是有很大的不同的,jMeter更多的是对rest api进行压测,而JMH关注的粒度更细,它更多的是发现某块性能槽点代码,然后对优化方案进行基准测试对比。 注意:JMH适合细粒度的方法测试,并不适用于系统之间的链路测试! 越复杂,结果越不可靠(more co

xinpz的博客 384

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

架构师Java 并发基准测试神器的-JMH,程序员必看!

架构师Java 并发基准测试神器的-JMH,程序员必看! 在Java编程这个行业里面性能测试这个话题非常庞大,我们可以从网络聊到操作系统,再从操作系统聊到内核,再从内核聊到你怀疑人生有木有。 先拍几个砖出来吧,我在写代码的时候经常有这种怀疑:写法A快还是写法B快,某个位置是用ArrayList还是LinkedList,HashMap还是TreeMap,HashMap的初始化size要不要指定,指...

cao123nba的博客 170

JMH:java官方推出的java基准测试神器

JMH(Java Microbenchmark Harness) 是 OpenJDK 官方出品的Java 微基准测试框架,专门测量纳秒~毫秒级短方法、代码片段性能,彻底解决手写计时(System.nanoTime)所有 JVM 陷阱。

秃了也弱了 515

JMH:让你的Java程序性能翻倍的神器

为什么拼接大量字符串,StringBuilder 比String 效率高 无论你是想优化现有的Java代码还是开发新的项目,JMH都能够帮助你准确、可靠地测量和分析代码的性能,让我们一起来探索JMH的神奇之处吧!JMH是由OpenJDK团队开发的一款专业的基准测试工具,旨在提供一个可靠的测试框架,帮助Java开发者进行代码性能的评估和优化。JMH是一款功能强大的Java性能测试工具,它能够帮助开发者准确、可靠地评估代码的性能,并为性能优化提供参考。

从零开始的博客 1079

Java微基准测试神器JMH初探

真可谓相见恨晚,上手也是非常迅速的,建议学习时间2小时,顺便看看官方GitHub仓库里面的错误示范,地址:https://github.com/lexburner/JMH-samples。这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!当我们实现一个需求,面临2种及以上的方案,选择一种性能更好的方案时,也需要进行一些快速的性能测试。当我们编写一段Java代码之后,如果想知道代码性能如何,就需要进行一些快速的性能测试。

主要分享测试的学习资源,帮助快速了解测试行业,帮助想转行、进阶、小白成长为高级测试工程师。 245

JMH:专治各种“我觉得挺快”的神器

网上关于“如何使用 JMH”的教程已经非常丰富,本文不再赘述其具体用法和代码编写细节。我们更关注的是:JMH 在哪些业务场景中真正发挥了价值?它解决了哪些实际问题?为什么我们需要它? 文末我整理了一些资源链接,有兴趣可以进一步学习。

weixin_53502673的博客 1082

测试和性能监控神器 JMH & Arthas

最近的工作日并不算太平,各种大大小小的case和解case,发现已经有好久好久没有静下心来专心写点东西了。不过倒还是坚持利用业余时间学习了不少微课上的东西,发现大佬们总结的东西还是不一样,...

天行健,君子以自强不息;地势坤,君子以厚德载物。 567

基准测试神器JMH实践-各类map性能对比

最近同事线上提交发布了一个变更,导致平响涨了几ms,仔细看了变更后发现只是一个map的put和get逻辑,这里使用的方式有点奇怪,key为string类型,但是其实是一个枚举转换而来,value是Double类型这里怀疑map是string类型导致,因为这里key是一个枚举转换而来,所以感觉是使用enummap类来使用性能更好,但是这里毕竟只是猜想,所以需要科学的数据来验证 , 这里就搭了下JMH环境来验证,分别来验证几种类型的性能情况:环境搭建可以参考:https://zhuanlan.zhihu.com

Primary_wind的专栏 481
上一篇: Tomcat 在 SpringBoot 中是如何启动的
下一篇: 别乱提交代码了,看下大厂 Git 提交规范是怎么做的!
公众号-芋道源码
博客等级 码龄10年 1636粉丝 377原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值