在java中使用JMH(Java Microbenchmark Harness)做性能测试
文章目錄
- 使用JMH做性能測(cè)試
- BenchmarkMode
- Fork和Warmup
- State和Scope
在java中使用JMH(Java Microbenchmark Harness)做性能測(cè)試
JMH的全稱是Java Microbenchmark Harness,是一個(gè)open JDK中用來做性能測(cè)試的套件。該套件已經(jīng)被包含在了JDK 12中。
本文將會(huì)講解如何使用JMH來在java中做性能測(cè)試。
如果你使用的不是JDK 12,那么需要添加如下依賴:
<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>使用JMH做性能測(cè)試
如果我們想測(cè)試某個(gè)方法的性能,一般來說就是重復(fù)執(zhí)行某個(gè)方法n次,求出總的執(zhí)行時(shí)間,然后求平均值。
但是這樣通常會(huì)有一些問題,比如程序的頭幾次執(zhí)行通常會(huì)比較慢,因?yàn)镴VM會(huì)對(duì)多次執(zhí)行的代碼進(jìn)行優(yōu)化。另外得出的統(tǒng)計(jì)結(jié)果也不夠直觀,需要我們自行解析。
如果使用JMH可以輕松解決這些問題。
在JMH中,將要測(cè)試的方法添加@Benchmark注解即可:
@Benchmarkpublic void measureThroughput() throws InterruptedException {TimeUnit.MILLISECONDS.sleep(100);}看下怎么調(diào)用:
public static void main(String[] args) throws RunnerException {Options opt = new OptionsBuilder().include(BenchMarkUsage.class.getSimpleName()) // .include(BenchMarkUsage.class.getSimpleName()+".*measureThroughput*")// 預(yù)熱3輪.warmupIterations(3)// 度量5輪.measurementIterations(5).forks(1).build();new Runner(opt).run();}上面的例子,我們通過OptionsBuilder的include方法添加了需要進(jìn)行測(cè)試的類。
默認(rèn)情況下,該類的所有@Benchmark方法都將會(huì)被測(cè)試,如果我們只想測(cè)試其中的某個(gè)方法,我們可以在類后面加上方法的名字:
.include(BenchMarkUsage.class.getSimpleName()+".*measureAll*")上面的代碼支持通配符。
warmupIterations(3)意思是在真正的執(zhí)行前,先熱身三次。
measurementIterations(5)表示我們將方法運(yùn)行5次來測(cè)試性能。
forks(1)表示啟動(dòng)一個(gè)進(jìn)程來執(zhí)行這個(gè)任務(wù)。
上面是最基本的運(yùn)行,我們看下運(yùn)行結(jié)果:
# JMH version: 1.19 # VM version: JDK 1.8.0_171, VM 25.171-b11 # VM invoker: /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/bin/java # VM options: -javaagent:/Applications/IntelliJ IDEA 2.app/Contents/lib/idea_rt.jar=55941:/Applications/IntelliJ IDEA 2.app/Contents/bin -Dfile.encoding=UTF-8 # Warmup: 3 iterations, 1 s each # Measurement: 5 iterations, 1 s each # Timeout: 10 min per iteration # Threads: 1 thread, will synchronize iterations # Benchmark mode: Throughput, ops/time # Benchmark: com.flydean.BenchMarkUsage.measureThroughput# Run progress: 26.66% complete, ETA 00:01:42 # Fork: 1 of 1 # Warmup Iteration 1: 9.727 ops/s # Warmup Iteration 2: 9.684 ops/s # Warmup Iteration 3: 9.678 ops/s Iteration 1: 9.652 ops/s Iteration 2: 9.678 ops/s Iteration 3: 9.733 ops/s Iteration 4: 9.651 ops/s Iteration 5: 9.678 ops/sResult "com.flydean.BenchMarkUsage.measureThroughput":9.678 ±(99.9%) 0.129 ops/s [Average](min, avg, max) = (9.651, 9.678, 9.733), stdev = 0.034CI (99.9%): [9.549, 9.808] (assumes normal distribution)ops/s 是每秒的OPS次數(shù)。程序會(huì)給出運(yùn)行的最小值,平均值和最大值。同時(shí)給出標(biāo)準(zhǔn)差stdev和置信區(qū)間CI。
BenchmarkMode
上面的例子中, 我們只用了最簡(jiǎn)單的@Benchmark。如果想實(shí)現(xiàn)更加復(fù)雜和自定義的BenchMark,我們可以使用@BenchmarkMode。
先舉個(gè)例子:
@Benchmark@BenchmarkMode(Mode.Throughput)@OutputTimeUnit(TimeUnit.SECONDS)public void measureThroughput() throws InterruptedException {TimeUnit.MILLISECONDS.sleep(100);}上面的例子中,我們指定了@BenchmarkMode(Mode.Throughput),Throughput的意思是整體吞吐量,表示給定的時(shí)間內(nèi)執(zhí)行的次數(shù)。
這里我們通過 @OutputTimeUnit(TimeUnit.SECONDS)來指定時(shí)間單位。
Mode除了Throughput還有如下幾種模式:
- AverageTime - 調(diào)用的平均時(shí)間
- SampleTime - 隨機(jī)取樣,最后輸出取樣結(jié)果的分布
- SingleShotTime - 只會(huì)執(zhí)行一次,通常用來測(cè)試?yán)鋯?dòng)時(shí)候的性能。
- All - 所有的benchmark modes。
Fork和Warmup
上面的例子中我們通過代碼來顯式的制定Fork和Warmup,我們也可以使用注解來實(shí)現(xiàn):
@Fork(value = 1, warmups = 2)@Warmup(iterations = 5)上面的例子中value表示該benchMark執(zhí)行多少次,warmups表示fork多少個(gè)進(jìn)程來執(zhí)行。iterations表示warmup的iterations個(gè)數(shù)。
如果你同時(shí)在代碼中和注解中都配置了相關(guān)的信息,那么注解將會(huì)覆蓋掉代碼中的顯示配置。
State和Scope
如果我們?cè)诙嗑€程環(huán)境中使用beachMark,那么多線程中用到的類變量是共享還是每個(gè)線程一個(gè)呢?
這個(gè)時(shí)候我們就要用到@State注解。
@State(Scope.Benchmark) public class StateUsage { }Scope有三種:
- Scope.Thread:默認(rèn)的State,每個(gè)測(cè)試線程分配一個(gè)實(shí)例;
- Scope.Benchmark:所有測(cè)試線程共享一個(gè)實(shí)例,用于測(cè)試有狀態(tài)實(shí)例在多線程共享下的性能;
- Scope.Group:每個(gè)線程組共享一個(gè)實(shí)例;
本文的例子可以參考https://github.com/ddean2009/learn-java-concurrency/tree/master/benchmark
更多精彩內(nèi)容且看:
- 區(qū)塊鏈從入門到放棄系列教程-涵蓋密碼學(xué),超級(jí)賬本,以太坊,Libra,比特幣等持續(xù)更新
- Spring Boot 2.X系列教程:七天從無(wú)到有掌握Spring Boot-持續(xù)更新
- Spring 5.X系列教程:滿足你對(duì)Spring5的一切想象-持續(xù)更新
- java程序員從小工到專家成神之路(2020版)-持續(xù)更新中,附詳細(xì)文章教程
更多教程請(qǐng)參考 flydean的博客
總結(jié)
以上是生活随笔為你收集整理的在java中使用JMH(Java Microbenchmark Harness)做性能测试的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java并发中CountDownLatc
- 下一篇: Java中IO和NIO的本质和区别