springboot整合JMH做优化实战

       这段时间接手项目出现各种问题,令人不胜烦扰。吐槽下公司做项目完全靠人堆,大上快上风格注定留下一地鸡毛,修修补补不如想如何提升同事代码水准免得背锅。偶然看到关于JMH对于优化java代码的直观性,于是有了这篇文章,希望能帮到大家。

一:基础介绍文章

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

这里介绍引入项目方式,各种基本注解用法,用例。比较全面,推荐大家学习

二:boot项目实用

注意事项:1.jdk版本大于9,最好使用的openJDK,其他的也行

                   2.做测试最好放在test包下,不影响正常项目使用

2-1 一般项目优化需求:

       一个简单方法,一个service接口(这个比较多。下面以这个为例)

场景1: 有个根据实例获取报警信息的接口  

        需求是要测试下,不同的多个实例对接口相应的影响,这里我分成1.2.3

直接test文件下新建

import com.chitic.things.device.api.request.monitor.AlarmSnsRequest;
import com.chitic.things.device.service.MonitorOnlineService;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.results.format.ResultFormatType;
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;

/**
 * 类功能说明: //
 *
 * @author Zhouxl
 * @date 2023/8/10 14:25
 */
@BenchmarkMode(Mode.AverageTime)  
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)  //仿JVM进行预热行为,提高命中率(1s 3次)
public class BenchmarkTest {

    private ConfigurableApplicationContext context;
    private MonitorOnlineService onlineService;

    @Setup
    public void init() {
        // 这里的WebApplication.class是项目里的spring boot启动类
        context = SpringApplication.run(CommonApplication.class);
        // 获取需要测试的bean
        this.onlineService = context.getBean(MonitorOnlineService.class);
    }

    @Benchmark
    public  void one(){
        AlarmSnsRequest snsRequest =new AlarmSnsRequest();
        String str="test";
        snsRequest.setSns(Arrays.asList(str.split(",")));
        //测试接口方法
        onlineService.alarmPageBySns(snsRequest);
    }

    @Benchmark
    public  void two(){
        AlarmSnsRequest snsRequest =new AlarmSnsRequest();
        String str="test,test1";
        snsRequest.setSns(Arrays.asList(str.split(",")));
        //测试接口方法
        onlineService.alarmPageBySns(snsRequest);
    }
    @Benchmark
    public  void three(){
        AlarmSnsRequest snsRequest =new AlarmSnsRequest();
        String str="test,test1,test2";
        snsRequest.setSns(Arrays.asList(str.split(",")));
        //测试接口方法
        onlineService.alarmPageBySns(snsRequest);
    }


    @TearDown
    public void down() {
        context.close();
    }

    public static void main(String[]  args)throws RunnerException {
        Options opts = new OptionsBuilder()
                .include(BenchmarkTest.class.getSimpleName())
                .resultFormat(ResultFormatType.JSON)   //导出json 可通过 http://deepoove.com/jmh-visual-chart/ 对比
                //.addProfiler(StackProfiler.class)      //栈内存解析,主要分析方法的耗时情况
                // .addProfiler(GCProfiler.class)           //JVM GC的情况 各区的情况(G1的垃圾回收器情况)
                //.addProfiler(HotspotMemoryProfiler.class)   //使用HotSpot VM 进行内存占用分析
                .forks(1)    //进程数
                .build();
        new Runner(opts).run();

    }
}

测试结果:1个时耗时大概0.38s,2个和3个消耗会增加,但区别不大

可以在项目中对任意接口进行测试,还可以图形化接口比较,直接体现你的优化价值

JMH Visual Chart      生成的json引入这里生成图标

2-2  接口分析需求

场景2: 有个接口一直导致卡死或者内存OOM,代码是依托答辩,看了头晕

这里就需要借助JVM对堆栈内存,找出耗时情况,哪种应对哪个情况我已经上面列出来了:

package com.chitic.demo.controller.demo;

import com.chitic.demo.Application;
import com.chitic.demo.controller.HartCheck;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.profile.GCProfiler;
import org.openjdk.jmh.profile.HotspotMemoryProfiler;
import org.openjdk.jmh.profile.StackProfiler;
import org.openjdk.jmh.results.format.ResultFormatType;
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;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * 类功能说明: //对堆栈和GC内部
 *
 * @author Zhouxl
 * @date 2023/8/10 14:59
 */
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)  //仿JVM进行预热行为,提高命中率(1s 3次)
public class JvmTest {

    private ConfigurableApplicationContext context;

    private HartCheck hartCheck;

    @Setup
    public void init() {
        // 这里的WebApplication.class是项目里的spring boot启动类
        context = SpringApplication.run(Application.class);
        // 获取需要测试的bean
        this.hartCheck = context.getBean(HartCheck.class);
    }

    @Benchmark
    public  void one(){
        //测试接口方法
        hartCheck.getUser();
    }



    @TearDown
    public void down() {
        context.close();
    }

    public static void main(String[]  args)throws RunnerException {
        Options opts = new OptionsBuilder()
                .include(JvmTest.class.getSimpleName())
                .addProfiler(StackProfiler.class)      //栈内存解析,主要分析方法的耗时情况
//                .addProfiler(GCProfiler.class)           //JVM GC的情况 各区的情况(G1的垃圾回收器情况)
//                .addProfiler(HotspotMemoryProfiler.class)   //使用HotSpot VM 进行内存分析
                .resultFormat(ResultFormatType.JSON)   //导出json 可通过 http://deepoove.com/jmh-visual-chart/ 对比
                .forks(1)    //进程数
                .build();
        new Runner(opts).run();

    }

}

2-2-1.addProfiler(StackProfiler.class)      //栈内存解析,主要分析方法的耗时情况

栈内存分析,主要看这些内容:

 就可以看到栈内耗时情况了,然后动手处理

2-2-2.addProfiler(GCProfiler.class) //JVM GC的情况 各区的情况(G1的垃圾回收器情况)

G1垃圾回收器的各种状态情况

2-2-3..addProfiler(HotspotMemoryProfiler.class)    //使用HotSpot VM 进行内存分析

展示数据和jstack的类似,能快速定位到哪些类占用内存,因为我的项目用的是graalvm17没办法用,只能各位自行探索了

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值