欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談Java基準性能測試之JMH

 更新時間:2021年06月30日 10:44:57   作者:Kevin.ZhangCG  
JMH是Java Microbenchmark Harness的簡稱,一個針對Java做基準測試的工具。想準確的對一段代碼做基準性能測試并不容易,因為JVM層面在編譯期、運行時對代碼做很多優(yōu)化,當代碼塊處于整個系統(tǒng)中運行時并不一定會生效,產(chǎn)生錯誤的基準測試結(jié)果,這個問題就是JMH要解決的

一、JMH vs JMeter

JMeter可能是最常用的性能測試工具。它既支持圖形界面,也支持命令行,屬于黑盒測試的范疇,對非開發(fā)人員比較友好,上手也非常容易。圖形界面一般用于編寫、調(diào)試測試用例,而實際的性能測試建議還是在命令行下運行。

很多場景下JMeter和JMH都可以做性能測試,但是對于嚴格意義上的基準測試來說,只有JMH才適合。JMeter的測試結(jié)果精度相對JVM較低、所以JMeter不適合于類級別的基準測試,更適合于對精度要求不高、耗時相對較長的操作。

JMeter測試精度差: JMeter自身框架比較重,舉個例子:使用JMH測試一個方法,平均耗時0.01ms,而使用JMeter測試的結(jié)果平均耗時20ms,相差200倍。JMeter內(nèi)置很多采樣器:JMeter內(nèi)置了支持多種網(wǎng)絡(luò)協(xié)議的采樣器,可以在不寫Java代碼的情況下實現(xiàn)很多復(fù)雜的測試。JMeter支持集群的方式運行,方便模擬多用戶、高并發(fā)壓力測試。

總結(jié): JMeter適合一些相對耗時的集成功能測試,如API接口的測試。JMH適合于類或者方法的單元測試。

二、JMH基本用法

2.1、創(chuàng)建JMH項目

官方推薦為JMH基準測試創(chuàng)建單獨的項目,最簡單的創(chuàng)建JMH項目的方法就是基于maven項目原型的方式創(chuàng)建(如果是在windows環(huán)境下,需要對org.open.jdk.jmh這樣帶.的用雙引號包裹)。

mvn archetype:generate

          -DinteractiveMode=false

          -DarchetypeGroupId=org.openjdk.jmh

          -DarchetypeArtifactId=jmh-java-benchmark-archetype

          -DarchetypeVersion=1.21

          -DgroupId=com.jenkov

          -DartifactId=first-benchmark

          -Dversion=1.0

可以看到生成的項目pom文件中主要是添加了兩個jmh
的依賴和設(shè)置了maven-shade-plugin的編譯方式(負責(zé)把項目的所有依賴jar包打入到目標jar包中,與springboot的實現(xiàn)方式類似)。

<dependencies>
        <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>
    </dependencies>
...
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.2</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <finalName>${uberjar.name}</finalName>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>org.openjdk.jmh.Main</mainClass>
                    </transformer>
                </transformers>
                <filters>
                    <filter>
                        <!--
                            Shading signed JARs will fail without this.
                            http://stackoverflow.com/questions/999489/invalid-signature-file-when-attempting-to-run-a-jar
                        -->
                        <artifact>*:*</artifact>
                        <excludes>
                            <exclude>META-INF/*.SF</exclude>
                            <exclude>META-INF/*.DSA</exclude>
                            <exclude>META-INF/*.RSA</exclude>
                        </excludes>
                    </filter>
                </filters>
            </configuration>
        </execution>
    </executions>
</plugin>

生成的項目中已經(jīng)包含了一個class文件MyBenchmark.java,如下:

public class MyBenchmark {

    @Benchmark
    public void testMethod() {
        // This is a demo/sample template for building your JMH benchmarks. Edit as needed.
        // Put your benchmark code here.
    }

}

2.2、編寫基準測試代碼

在上面生成的MyBenchmark類的testMethod中就可以添加基準測試的java代碼,舉例如下:測試AtomicInteger的incrementAndGet的基準性能。

public class MyBenchmark {
    static AtomicInteger integer = new AtomicInteger();

    @Benchmark
    public void testMethod() {
        // This is a demo/sample template for building your JMH benchmarks. Edit as needed.
        // Put your benchmark code here.
        integer.incrementAndGet();
    }
}

2.3、JMH打包、運行

項目打包

mvn clean install

運行生成的目標jar包benchmark.jar:

java -jar benchmark.jar

# JMH version: 1.21

# VM version: JDK 1.8.0_181, Java HotSpot(TM) 64-Bit Server VM, 25.181-b13

# VM invoker: C:\Java\jdk1.8.0_181\jre\bin\java.exe

# VM options: <none>

# Warmup: 5 iterations, 10 s each

# Measurement: 5 iterations, 10 s each

# Timeout: 10 min per iteration

# Threads: 1 thread, will synchronize iterations

# Benchmark mode: Throughput, ops/time

# Benchmark: org.sample.MyBenchmark.testMethod

# Run progress: 0.00% complete, ETA 00:01:40

# Fork: 1 of 1

# Warmup Iteration   1: 81052462.185 ops/s

# Warmup Iteration   2: 80152956.333 ops/s

# Warmup Iteration   3: 81305026.522 ops/s

# Warmup Iteration   4: 81740215.227 ops/s

# Warmup Iteration   5: 82398485.097 ops/s

Iteration   1: 82176523.804 ops/s

Iteration   2: 81818881.730 ops/s

Iteration   3: 82812749.807 ops/s

Iteration   4: 82406672.531 ops/s

Iteration   5: 74270344.512 ops/s

Result "org.sample.MyBenchmark.testMethod":

  80697034.477 ±(99.9%) 13903555.960 ops/s [Average]

  (min, avg, max) = (74270344.512, 80697034.477, 82812749.807), stdev = 3610709.330

  CI (99.9%): [66793478.517, 94600590.437] (assumes normal distribution)

# Run complete. Total time: 00:01:41

REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on

why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial

experiments, perform baseline and negative tests that provide experimental control, make sure

the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.

Do not assume the numbers tell you what you want them to tell.

Benchmark                Mode  Cnt         Score          Error  Units

MyBenchmark.testMethod  thrpt    5  80697034.477 ± 13903555.960  ops/s

從上面的日志我們大致可以了解到 JMH的基準測試主要經(jīng)歷了下面幾個過程:

1.打印本次測試的配置,warmup:5輪;measurement:5輪;每輪:10s;啟動1個線程做測試;基準測試指標:吞吐量(throughput,單位是s);測試方法MyBenchmark.testMethod

2.啟動一個JVM進程做基準測試(也可以設(shè)置啟動多個進程,減少隨機因素的誤差影響)

3.在JVM進程中先執(zhí)行了5輪的預(yù)熱(warmup),每輪10s,總共50s的預(yù)熱時間。預(yù)熱的數(shù)據(jù)不作為基準測試的參考。

4.測試了5輪,每輪10s,總共50s的測試時間

5.匯總測試數(shù)據(jù)、生成結(jié)果報表。最終結(jié)論是吞吐量(80697034.477 ±13903555.960 ops/s),其中80697034.477 是結(jié)果,13903555.960是誤差范圍。

2.4、JMH與Springboot

在對Springboot項目做JMH基準測試時可能會因為maven-shade-plugin插件的問題打包報錯,需要在JMH的maven-shade-plugin的插件配置中添加id即可。項目的pom可能如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.7.RELEASE</version>
        <relativePath/>
    </parent>
...
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.2</version>
    <executions>
        <execution>
            <!-- 需要在此處添加一個id標簽,否則mvn package時會報錯 -->
            <id>shade-all-dependency-jar</id>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                ...
            </configuration>
        </execution>
    </executions>
</plugin>
...
</project>

在測試代碼中正?;赟pringBootApplication構(gòu)建ConfigurableApplicationContext從而獲取bean的方式獲取對象測試即可。

public class StringRedisTemplateBenchmark  {
    StringRedisTemplate redisTemplate;
            
    @Setup(Level.Trial)
    public void setUp() {
        redisTemplate = SpringApplication.run(SpringBootApplicationClass.class).getBean(StringRedisTemplate.class);
    }
    
    @Benchmark
    public void testGet() {
        redisTemplate.opsForValue().get("testkey");
    }
}

@SpringBootApplication
public class SpringBootApplicationClass {

}

application.properties

lettuce.pool.maxTotal=50
lettuce.pool.maxIdle=10
lettuce.pool.minIdle=0

lettuce.sentinel.master=mymaster
lettuce.sentinel.nodes=10.xx.xx.xx:26379,10.xx.xx.xx:26379
lettuce.password=xxxxxx

三、JMH注解

JMH測試的相關(guān)配置大多是通過注解的方式體現(xiàn)的。

具體每個注解的使用實例也可以參考官網(wǎng)

http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/

3.1、JMH Benchmark Modes

JMH benchmark支持如下幾種測試模式:

  • Throughput: 吞吐量,測試每秒可以執(zhí)行操作的次數(shù)
  • Average Time: 平均耗時,測試單次操作的平均耗時
  • Sample Time:采樣耗時,測試單次操作的耗時,包括最大、最小耗時,已經(jīng)百分位耗時等
  • Single Shot Time: 只計算一次的耗時,一般用來測試冷啟動的性能(不設(shè)置JVM預(yù)熱)
  • All: 測試上面的所有指標

默認的benchmark mode是Throughput,可以通過注解的方式設(shè)置BenchmarkMode,注解支持放在類或方法上。如下所示設(shè)置了Throughput和SampleTime兩個Benchmark mode。

@BenchmarkMode({Mode.Throughput, Mode.SampleTime})
public class MyBenchmark {
    static AtomicInteger integer = new AtomicInteger();

    @Benchmark
    public void testMethod() {
        // This is a demo/sample template for building your JMH benchmarks. Edit as needed.
        // Put your benchmark code here.
        integer.incrementAndGet();
    }
}

3.2、Benchmark Time Units

JMH支持設(shè)置打印基準測試結(jié)果的時間單位,通過@OutputTimeUnit注解的方式設(shè)置。

@OutputTimeUnit(TimeUnit.SECONDS)
public class MyBenchmark {
    static AtomicInteger integer = new AtomicInteger();

    @Benchmark
    public void testMethod() {
        integer.incrementAndGet();
    }

}

3.3、Benchmark State

有時候我們在做基準測試的時候會需要使用一些變量、字段,@State注解是用來配置這些變量的生命周期,@State注解可以放在類上,然后在基準測試方法中可以通過參數(shù)的方式把該類對象作為參數(shù)使用。@State支持的生命周期類型:

  • Benchmark: 整個基準測試的生命周期,多個線程共用同一份實例對象。該類內(nèi)部的@Setup @TearDown注解的方法可能會被任一個線程執(zhí)行,但是只會執(zhí)行一次。
  • Group: 每一個Group內(nèi)部共享同一個實例,需要配合@Group @GroupThread使用。該類內(nèi)部的@Setup @TearDown注解的方法可能會該Group內(nèi)的任一個線程執(zhí)行,但是只會執(zhí)行一次。
  • Thread:每個線程的實例都是不同的、唯一的。該類內(nèi)部的@Setup @TearDown注解的方法只會被當前線程執(zhí)行,而且只會執(zhí)行一次。

被@State標示的類必須滿足如下兩個要求:

類必須是public的

必須有無參構(gòu)造函數(shù)

3.4、State Object @Setup @TearDown

在@Scope注解標示的類的方法上可以添加@Setup和@TearDwon注解。@Setup:用來標示在Benchmark方法使用State對象之前需要執(zhí)行的操作。@TearDown:用來標示在Benchmark方法之后需要對State對象執(zhí)行的操作。
如下示例:

@OutputTimeUnit(TimeUnit.SECONDS)
public class MyBenchmark {
    
    @Benchmark
    public void testMethod(TestAddAndGetState state) {
        state.getInteger().incrementAndGet();
    }

    @State(Scope.Benchmark)
    public static class TestAddAndGetState {
        private AtomicInteger integer;

        @Setup(Level.Iteration)
        public void setup() {
            integer = new AtomicInteger();
        }

        public AtomicInteger getInteger() {
            return integer;
        }
    }
}

@Setup、@TearDown支持設(shè)置Level級別,Level有三個值:

  • Trial: 每次benchmark前/后執(zhí)行一次,每次benchmark會包含多輪(Iteration)
  • Iteration: 每輪執(zhí)行前/后執(zhí)行一次
  • Invocation: 每次調(diào)用測試的方法前/后都執(zhí)行一次,這個執(zhí)行頻率會很高,一般用不上。

3.5、Fork

@Fork注解用來設(shè)置啟動的JVM進程數(shù)量,多個進程是串行的方式啟動的,多個進程可以減少偶發(fā)因素對測試結(jié)果的影響。

3.6、Thread

@Thread用來配置執(zhí)行測試啟動的線程數(shù)量

3.7、Warmup

@Warmup 用來配置預(yù)熱的時間,如下所示配置預(yù)熱五輪,每輪1second,也就是說總共會預(yù)熱5s左右,在這5s內(nèi)會不停的循環(huán)調(diào)用測試方法,但是預(yù)熱時的數(shù)據(jù)不作為測試結(jié)果參考。

@Warmup(iterations = 5, time = 1)

3.8、Measurement

@Measurement用來配置基準測試的時間,如下所示配置預(yù)熱10輪,每輪1second,也就是說總共會測試10s左右,在這10s內(nèi)會不停的循環(huán)調(diào)用測試方法,同事測試數(shù)據(jù)會被基準測試結(jié)果參考。

@Measurement(iterations = 5, time = 1)

四、輸出測試結(jié)果

jmh支持多種格式的結(jié)果輸出text, csv, scsv, json, latex

如下打印出json格式的:

java -jar benchmark.jar -rf json

以上就是淺談Java基準性能測試之JMH的詳細內(nèi)容,更多關(guān)于Java基準性能測試 JMH的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java使用lambda自定義Arrays.sort排序規(guī)則說明

    Java使用lambda自定義Arrays.sort排序規(guī)則說明

    這篇文章主要介紹了Java使用lambda自定義Arrays.sort排序規(guī)則說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • JDK1.8中的ConcurrentHashMap使用及場景分析

    JDK1.8中的ConcurrentHashMap使用及場景分析

    這篇文章主要介紹了JDK1.8中的ConcurrentHashMap使用及場景分析,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • Java中List集合去重方法以及效率對比

    Java中List集合去重方法以及效率對比

    這篇文章主要給大家介紹了關(guān)于Java中List集合去重方法以及效率對比的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • IDEA怎么生成UML類圖的實現(xiàn)

    IDEA怎么生成UML類圖的實現(xiàn)

    這篇文章主要介紹了IDEA怎么生成UML類圖的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Spring基于注解管理bean實現(xiàn)方式講解

    Spring基于注解管理bean實現(xiàn)方式講解

    很多時候我們需要根據(jù)不同的條件在容器中加載不同的Bean,或者根據(jù)不同的條件來選擇是否在容器中加載某個Bean,這就是Bean的加載控制,一般我們可以通過編程式或注解式兩種不同的方式來完成Bean的管理
    2023-01-01
  • SpringBoot 使用 FTP 操作文件的過程(刪除、上傳、下載文件)

    SpringBoot 使用 FTP 操作文件的過程(刪除、上傳、下載文件)

    這篇文章主要介紹了SpringBoot 使用 FTP 操作文件,主要包括配置ftp服務(wù)器,上傳、刪除、下載文件操作,本文結(jié)合示例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-12-12
  • java后臺判斷客戶端是手機/PC并返回不同頁面的實例

    java后臺判斷客戶端是手機/PC并返回不同頁面的實例

    下面小編就為大家分享一篇java后臺判斷客戶端是手機/PC并返回不同頁面的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-01-01
  • 簡單了解JAVA內(nèi)存泄漏和溢出區(qū)別及聯(lián)系

    簡單了解JAVA內(nèi)存泄漏和溢出區(qū)別及聯(lián)系

    這篇文章主要介紹了簡單了解JAVA內(nèi)存泄漏和溢出區(qū)別及聯(lián)系,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03
  • 解析Java的可變長參數(shù)列表及其使用時的注意點

    解析Java的可變長參數(shù)列表及其使用時的注意點

    這篇文章主要介紹了解析Java的可變參數(shù)列表及其使用時的注意點,注意可變參數(shù)必須位于最后一項,需要的朋友可以參考下
    2016-03-03
  • Java接口定義與實現(xiàn)方法分析

    Java接口定義與實現(xiàn)方法分析

    這篇文章主要介紹了Java接口定義與實現(xiàn)方法,簡單說明了接口的概念、功能,并結(jié)合實例形式分析了接口的相關(guān)定義與使用技巧,需要的朋友可以參考下
    2017-11-11

最新評論