南昌网站建设58,注册公司流程 上海,海外访问国内网站 dns,大中型企业网络设计方案文章目录 1、JMH2、运行方式二3、死代码与黑洞变量4、可视化分析5、案例#xff1a;日期格式化方法性能测试6、总结7、整合到SpringBoot 判断一个方法的耗时 ⇒ endTime-startTime ⇒ 不准确#xff0c;首先部分对象懒加载#xff0c;第一次请求会慢一些#xff0c;其次日期格式化方法性能测试6、总结7、整合到SpringBoot 判断一个方法的耗时 ⇒ endTime-startTime ⇒ 不准确首先部分对象懒加载第一次请求会慢一些其次程序运行时JIT即时编译器会实时优化代码如随着执行次数的增加程序性能逐渐优化 ⇒ JMHJava Microbenchmark Harness准确的测方法执行的性能
1、JMH
https://github.com/openjdk/jmhJMH会先执行预热确保JIT队代码优化之后再进行测试 JMH项目搭建新建个空目录执行mvn生成模块 mvn archetype:generate \
-DinteractiveModefalse \
-DarchetypeGroupIdorg.openjdk.jmh \
-DarchetypeArtifactIdjmh-java-benchmark-archetype \
-DgroupIdorg.sample \
-DartifactIdtest \
-Dversion1.0写一个简单案例
//执行5轮预热每次持续1秒
Warmup(iterations 5, time 1, timeUnit TimeUnit.SECONDS)
//启动多少个进程 追加JMV参数
Fork(value 1, jvmArgsAppend {-Xms1g, -Xmx1g})
//指定显示平均时间单位纳秒。Mode.ALL显示所有数据
BenchmarkMode(Mode.AverageTime)
//纳秒
OutputTimeUnit(TimeUnit.NANOSECONDS)
//变量共享的范围对象在单个线程中共享就选Scope.Thread
State(Scope.Benchmark)
public class MyBenchmark {Benchmarkpublic int test1() {int i 0;i;return i;}}mvn verfiy校验并生成jar包 运行服务得到结果 2、运行方式二
每次打jar包运行很麻烦改用一个main方法
//执行5轮预热每次持续1秒
Warmup(iterations 5, time 1, timeUnit TimeUnit.SECONDS)
//启动多少个进程 追加JMV参数
Fork(value 1, jvmArgsAppend {-Xms1g, -Xmx1g})
//指定显示平均时间单位纳秒。Mode.ALL显示所有数据
BenchmarkMode(Mode.AverageTime)
//纳秒
OutputTimeUnit(TimeUnit.NANOSECONDS)
//变量共享的范围对象在单个线程中共享就选Scope.Thread
State(Scope.Benchmark)
public class MyBenchmark {Benchmarkpublic int test1() {int i 0;i;return i;}public static void main(String[] args) throws RunnerException {Options opt new OptionsBuilder()//测哪个类.include(MyBenchmark.class.getSimpleName())//结果的格式json文件//.resultFormat(ResultFormatType.JSON)//进程数.forks(1).build();new Runner(opt).run();}
}结果相比jar包运行的方式略有出入因为IDEA启动时自身会设置一些参数所以要准确就建议用jar的方式 3、死代码与黑洞变量
如下定义的变量i最后没有返回JIT会认为i没有使用会把这一段代码自动忽略掉
//...
public void testMethod() {int i 0;i;}
//...此时JMH返回的结果明显下降很多 以上即死代码JMH测试过程中可用一个黑洞的变量调用consume消费方法就可以避免JIT把这些变量自动删除掉
public void testMethod(Blackhole blackhole) {int i 0;i;int j 0;j;//使用黑洞避免i,j变量没有使用被JIT当成死代码优化时去掉blackhole.consume(i);blackhole.consume(j);
}4、可视化分析
生成json格式
//....resultFormat(ResultFormatType.JSON)上传到https://jmh.morethan.io/ 5、案例日期格式化方法性能测试
package org.sample;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;import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.concurrent.TimeUnit;//执行5轮预热每次持续1秒
Warmup(iterations 5, time 1, timeUnit TimeUnit.SECONDS)
//执行一次测试
Fork(value 1, jvmArgsAppend {-Xms1g, -Xmx1g})
//显示平均时间单位纳秒
BenchmarkMode(Mode.AverageTime)
OutputTimeUnit(TimeUnit.NANOSECONDS)
State(Scope.Thread)
public class DateBench {private static String sDateFormatString yyyy-MM-dd HH:mm:ss;private Date date new Date();private LocalDateTime localDateTime LocalDateTime.now();//优化private static ThreadLocalSimpleDateFormat simpleDateFormatThreadLocal new ThreadLocal();private static final DateTimeFormatter formatter DateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss);Setuppublic void setUp() {SimpleDateFormat sdf new SimpleDateFormat(sDateFormatString);simpleDateFormatThreadLocal.set(sdf);}//测试DateBenchmarkpublic String date() {SimpleDateFormat simpleDateFormat new SimpleDateFormat(sDateFormatString);return simpleDateFormat.format(date);}//测试LocalDateTimeBenchmarkpublic String localDateTimeNotSave() {return localDateTime.format(DateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss));}/*** 优化测试Date的方法* SimpleDateFormat线程不安全用ThreadLocal优化* 避免每次执行都创建一个SimpleDateFormat对象*/Benchmarkpublic String dateThreadLocal() {return simpleDateFormatThreadLocal.get().format(date);}/*** 优化LocalDateTime*/Benchmarkpublic String localDateTime() {return localDateTime.format(formatter);}public static void main(String[] args) throws RunnerException {Options opt new OptionsBuilder().include(DateBench.class.getSimpleName()).resultFormat(ResultFormatType.JSON).forks(1).build();new Runner(opt).run();}
}结果 结论
Date对象使用的SimpleDateFormat线程不安全每次需要重新创建对象或者将对象放入ThreadLocal后者性能好一点LocalDateTime对象使用的DateTimeFormatter线程安全且性能好将DateTimeFormatter对象保存一下别每次都创建性能会更好
6、总结
Jmh可以完全模拟运行环境中的Java虚拟机参数同时支持预热能通过JIT执行优化后的代码获得更为准确的数据
7、整合到SpringBoot
dependencygroupIdorg.openjdk.jmh/groupIdartifactIdjmh-core/artifactIdversion${jmh.version}/versionscopetest/scope
/dependencydependencygroupIdorg.openjdk.jmh/groupIdartifactIdjmh-generator-annprocess/artifactIdversion${jmh.version}/versionscopetest/scope
/dependency和之前单独一个jmh项目相比整合时可在UT中完成setup初始是从IOC中获取要测试的方法所在类的Bean。且每次执行Benchmark注解的方法都会运行一个新的SpringBoot服务下面同时测5个方法因此需要在配置文件中将端口设置成随机生成的。
import org.junit.jupiter.api.Test;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
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.OptionsBuilder;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext;import java.io.IOException;
import java.util.concurrent.TimeUnit;//执行5轮预热每次持续1秒
Warmup(iterations 5, time 1, timeUnit TimeUnit.SECONDS)
//执行一次测试
Fork(value 1, jvmArgsAppend {-Xms1g, -Xmx1g})
//显示平均时间单位纳秒
BenchmarkMode(Mode.AverageTime)
OutputTimeUnit(TimeUnit.MILLISECONDS)
State(Scope.Benchmark)
public class PracticeBenchmarkTest {private UserController userController;private ApplicationContext context;//初始化将springboot容器启动 端口号随机Setuppublic void setup() {this.context new SpringApplication(JvmOptimizeApplication.class).run();userController this.context.getBean(UserController.class);}//启动这个测试用例进行测试Testpublic void executeJmhRunner() throws RunnerException, IOException {new Runner(new OptionsBuilder().shouldDoGC(true).forks(0).resultFormat(ResultFormatType.JSON).shouldFailOnError(true).build()).run();}//用黑洞消费数据避免JIT消除代码Benchmarkpublic void test1(final Blackhole bh) {bh.consume(userController.user1());}Benchmarkpublic void test2(final Blackhole bh) {bh.consume(userController.user2());}Benchmarkpublic void test3(final Blackhole bh) {bh.consume(userController.user3());}Benchmarkpublic void test4(final Blackhole bh) {bh.consume(userController.user4());}Benchmarkpublic void test5(final Blackhole bh) {bh.consume(userController.user5());}
}随机端口
server:
# port: 8882port: ${random.int(2000,8000)} #tomcat:threads:min-spare: 50max: 500