别再写 main 方法测试了,太 Low!这才是专业 Java 测试方法! 上

简介: 别再写 main 方法测试了,太 Low!这才是专业 Java 测试方法! 上



前言

"If you cannot measure it, you cannot improve it".

在日常开发中,我们对一些代码的调用或者工具的使用会存在多种选择方式,在不确定他们性能的时候,我们首先想要做的就是去测量它。大多数时候,我们会简单的采用多次计数的方式来测量,来看这个方法的总耗时。

但是,如果熟悉JVM类加载机制的话,应该知道JVM默认的执行模式是JIT编译与解释混合执行。JVM通过热点代码统计分析,识别高频方法的调用、循环体、公共模块等,基于JIT动态编译技术,会将热点代码转换成机器码,直接交给CPU执行。

也就是说,JVM会不断的进行编译优化,这就使得很难确定重复多少次才能得到一个稳定的测试结果?所以,很多有经验的同学会在测试代码前写一段预热的逻辑。

JMH,全称 Java Microbenchmark Harness (微基准测试框架),是专门用于Java代码微基准测试的一套测试工具API,是由 OpenJDK/Oracle 官方发布的工具。何谓 Micro Benchmark 呢?简单地说就是在 method 层面上的 benchmark,精度可以精确到微秒级。

Java的基准测试需要注意的几个点:

  • 测试前需要预热。
  • 防止无用代码进入测试方法中。
  • 并发测试。
  • 测试结果呈现。

JMH的使用场景:

  1. 定量分析某个热点函数的优化效果
  2. 想定量地知道某个函数需要执行多长时间,以及执行时间和输入变量的相关性
  3. 对比一个函数的多种实现方式

本篇主要是介绍JMH的DEMO演示,和常用的注解参数。希望能对你起到帮助。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

DEMO 演示

这里先演示一个DEMO,让不了解JMH的同学能够快速掌握这个工具的大概用法。

1. 测试项目构建

JMH是内置Java9及之后的版本。这里是以Java8进行说明。

为了方便,这里直接介绍使用maven构建JMH测试项目的方式。

第一种是使用命令行构建,在指定目录下执行以下命令:

$ mvn archetype:generate \
          -DinteractiveMode=false \
          -DarchetypeGroupId=org.openjdk.jmh \
          -DarchetypeArtifactId=jmh-java-benchmark-archetype \
          -DgroupId=org.sample \
          -DartifactId=test \
          -Dversion=1.0

对应目录下会出现一个test项目,打开项目后我们会看到这样的项目结构。

第二种方式就是直接在现有的maven项目中添加jmh-corejmh-generator-annprocess的依赖来集成JMH。

<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-core</artifactId>
    <version>${jmh.version}</version>
</dependency>
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-generator-annprocess</artifactId>
    <version>${jmh.version}</version>
    <scope>provided</scope>
</dependency>

2. 编写性能测试

这里我以测试LinkedList 通过index 方式迭代和foreach 方式迭代的性能差距为例子,编写测试类,涉及到的注解在之后会讲解。

/**
 * @author Richard_yyf
 * @version 1.0 2019/8/27
 */
@State(Scope.Benchmark)
@OutputTimeUnit(TimeUnit.SECONDS)
@Threads(Threads.MAX)
public class LinkedListIterationBenchMark {
 private static final int SIZE = 10000;
    private List<String> list = new LinkedList<>();
    @Setup
    public void setUp() {
        for (int i = 0; i < SIZE; i++) {
            list.add(String.valueOf(i));
        }
    }
    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    public void forIndexIterate() {
        for (int i = 0; i < list.size(); i++) {
            list.get(i);
            System.out.print("");
        }
    }
    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    public void forEachIterate() {
        for (String s : list) {
            System.out.print("");
        }
    }
}

3. 执行测试

运行 JMH 基准测试有两种方式,一个是生产jar文件运行,另一个是直接写main函数或者放在单元测试中执行。

生成jar文件的形式主要是针对一些比较大的测试,可能对机器性能或者真实环境模拟有一些需求,需要将测试方法写好了放在linux环境执行。

具体命令如下

$ mvn clean install
$ java -jar target/benchmarks.jar

我们日常中遇到的一般是一些小测试,比如我上面写的例子,直接在IDE中跑就好了。

启动方式如下:

public static void main(String[] args) throws RunnerException {
    Options opt = new OptionsBuilder()
            .include(LinkedListIterationBenchMark.class.getSimpleName())
            .forks(1)
            .warmupIterations(2)
            .measurementIterations(2)
         .output("E:/Benchmark.log")
            .build();
    new Runner(opt).run();
}
相关文章
|
24天前
|
数据采集 监控 机器人
浅谈网页端IM技术及相关测试方法实践(包括WebSocket性能测试)
最开始转转的客服系统体系如IM、工单以及机器人等都是使用第三方的产品。但第三方产品对于转转的业务,以及客服的效率等都产生了诸多限制,所以我们决定自研替换第三方系统。下面主要分享一下网页端IM技术及相关测试方法,我们先从了解IM系统和WebSocket开始。
43 4
|
1月前
|
消息中间件 Java Kafka
在Java中实现分布式事务的常用框架和方法
总之,选择合适的分布式事务框架和方法需要综合考虑业务需求、性能、复杂度等因素。不同的框架和方法都有其特点和适用场景,需要根据具体情况进行评估和选择。同时,随着技术的不断发展,分布式事务的解决方案也在不断更新和完善,以更好地满足业务的需求。你还可以进一步深入研究和了解这些框架和方法,以便在实际应用中更好地实现分布式事务管理。
|
1月前
|
Java
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
75 9
|
21天前
|
安全 Ubuntu Linux
Metasploit Pro 4.22.6-2024111901 (Linux, Windows) - 专业渗透测试框架
Metasploit Pro 4.22.6-2024111901 (Linux, Windows) - 专业渗透测试框架
42 9
Metasploit Pro 4.22.6-2024111901 (Linux, Windows) - 专业渗透测试框架
|
1天前
|
Java Maven
java项目中jar启动执行日志报错:no main manifest attribute, in /www/wwwroot/snow-server/z-server.jar-jar打包的大小明显小于正常大小如何解决
在Java项目中,启动jar包时遇到“no main manifest attribute”错误,且打包大小明显偏小。常见原因包括:1) Maven配置中跳过主程序打包;2) 缺少Manifest文件或Main-Class属性。解决方案如下:
java项目中jar启动执行日志报错:no main manifest attribute, in /www/wwwroot/snow-server/z-server.jar-jar打包的大小明显小于正常大小如何解决
|
1月前
|
机器学习/深度学习 算法 UED
在数据驱动时代,A/B 测试成为评估机器学习项目不同方案效果的重要方法
在数据驱动时代,A/B 测试成为评估机器学习项目不同方案效果的重要方法。本文介绍 A/B 测试的基本概念、步骤及其在模型评估、算法改进、特征选择和用户体验优化中的应用,同时提供 Python 实现示例,强调其在确保项目性能和用户体验方面的关键作用。
36 6
|
1月前
|
安全 Java 开发者
Java中WAIT和NOTIFY方法必须在同步块中调用的原因
在Java多线程编程中,`wait()`和`notify()`方法是实现线程间协作的关键。这两个方法必须在同步块或同步方法中调用,这一要求背后有着深刻的原因。本文将深入探讨为什么`wait()`和`notify()`方法必须在同步块中调用,以及这一机制如何确保线程安全和避免死锁。
44 4
|
1月前
|
Java
深入探讨Java中的中断机制:INTERRUPTED和ISINTERRUPTED方法详解
在Java多线程编程中,中断机制是协调线程行为的重要手段。了解和正确使用中断机制对于编写高效、可靠的并发程序至关重要。本文将深入探讨Java中的`Thread.interrupted()`和`Thread.isInterrupted()`方法的区别及其应用场景。
39 4
|
1月前
|
Java 数据处理 数据安全/隐私保护
Java处理数据接口方法
Java处理数据接口方法
26 1
|
1月前
|
JavaScript 安全 编译器
TypeScript 与 Jest 测试框架的结合使用,从 TypeScript 的测试需求出发,介绍了 Jest 的特点及其与 TypeScript 结合的优势,详细讲解了基本测试步骤、常见测试场景及异步操作测试方法
本文深入探讨了 TypeScript 与 Jest 测试框架的结合使用,从 TypeScript 的测试需求出发,介绍了 Jest 的特点及其与 TypeScript 结合的优势,详细讲解了基本测试步骤、常见测试场景及异步操作测试方法,并通过实际案例展示了其在项目中的应用效果,旨在提升代码质量和开发效率。
47 6