日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

不要再用main方法测试代码性能了,用这款JDK自带工具

發(fā)布時(shí)間:2025/3/11 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 不要再用main方法测试代码性能了,用这款JDK自带工具 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

作為軟件開(kāi)發(fā)人員,我們通常會(huì)寫(xiě)一些測(cè)試程序用來(lái)對(duì)比不同算法、不同工具的性能問(wèn)題。而最常見(jiàn)的做法是寫(xiě)一個(gè)main方法,構(gòu)造模擬場(chǎng)景進(jìn)行并發(fā)測(cè)試。

如果細(xì)心的朋友可能已經(jīng)發(fā)現(xiàn),每次測(cè)試結(jié)果誤差很大,有時(shí)候測(cè)試出的結(jié)果甚至與事實(shí)相反。當(dāng)然,這不排除是因?yàn)檐浻布h(huán)境因素導(dǎo)致,但更多的可能是因?yàn)樗褂脺y(cè)試方法自身有問(wèn)題。

比如,不同需要性能比較方法放到一個(gè)虛擬機(jī)里調(diào)用,有可能會(huì)互相影響,缺少預(yù)熱的過(guò)程等。

本文給大家推薦一款JDK9及以后自帶的一款可用于軟件基準(zhǔn)測(cè)試的工具JMH(Java Microbenchmark Harness)。

JMH簡(jiǎn)介

JMH是用于代碼微基準(zhǔn)測(cè)試的工具套件,主要是基于方法層面的基準(zhǔn)測(cè)試,精度可以達(dá)到納秒級(jí)。

何謂Micro Benchmark呢?簡(jiǎn)單的來(lái)說(shuō)就是基于方法層面的基準(zhǔn)測(cè)試,精度可以達(dá)到微秒級(jí)。當(dāng)你定位到熱點(diǎn)方法,希望進(jìn)一步優(yōu)化方法性能的時(shí)候,就可以使用JMH對(duì)優(yōu)化的結(jié)果進(jìn)行量化的分析。

這款工具是由Oracle內(nèi)部實(shí)現(xiàn)JIT的作者所寫(xiě)。我們知道JIT(Java即時(shí)編譯器)是將JVM優(yōu)化的所有高效手段和技術(shù)都使用上的地方??上攵?#xff0c;開(kāi)發(fā)者比任何人都更加了解JVM和JIT對(duì)基準(zhǔn)測(cè)試的影響。

因此,這款工具是值得我們信賴(lài)和在實(shí)踐中進(jìn)行使用的。而且使用起來(lái)也非常方便。

使用場(chǎng)景

JMH不僅能幫我們測(cè)試一些常見(jiàn)類(lèi)的性能,比如對(duì)比StringBuffer和StringBuilder的性能、對(duì)比不同算法的在不同數(shù)據(jù)量的性能等,還能夠幫助我們對(duì)系統(tǒng)中發(fā)現(xiàn)的熱點(diǎn)代碼進(jìn)行量化分析。

JMH通常用于以下應(yīng)用場(chǎng)景:

  • 測(cè)試某個(gè)方法在穩(wěn)定執(zhí)行的情況下所需時(shí)間,以及執(zhí)行時(shí)間和問(wèn)題規(guī)模的相關(guān)性;

  • 對(duì)比接口不同實(shí)現(xiàn)在給定條件下的吞吐量

  • 查看多少百分比的請(qǐng)求在多長(zhǎng)時(shí)間內(nèi)完成

使用實(shí)例

依賴(lài)引入

如果你使用的是JDK9或以上版本,則JDK中已經(jīng)自帶了該工具,直接使用即可。如果你使用的是其他版本則可以通過(guò)maven直接引入以下依賴(lài):

<dependency><groupId>org.openjdk.jmh</groupId><artifactId>jmh-core</artifactId><version>1.27</version> </dependency> <dependency><groupId>org.openjdk.jmh</groupId><artifactId>jmh-generator-annprocess</artifactId><version>1.27</version> </dependency>

其中1.27是當(dāng)前的最新版本,可根據(jù)實(shí)際需要更新或降低版本。

測(cè)試案例

下面以StringBuffer和StringBuilder的性能測(cè)試對(duì)比為例來(lái)進(jìn)行基準(zhǔn)測(cè)試。

//使用模式?默認(rèn)是Mode.Throughput @BenchmarkMode(Mode.AverageTime) //?配置預(yù)熱次數(shù),默認(rèn)是每次運(yùn)行1秒,運(yùn)行10次,這里設(shè)置為3次 @Warmup(iterations?=?3,?time?=?1) //?本例是一次運(yùn)行4秒,總共運(yùn)行3次,在性能對(duì)比時(shí)候,采用默認(rèn)1秒即可 @Measurement(iterations?=?3,?time?=?4) //?配置同時(shí)起多少個(gè)線程執(zhí)行 @Threads(1) //代表啟動(dòng)多個(gè)單獨(dú)的進(jìn)程分別測(cè)試每個(gè)方法,這里指定為每個(gè)方法啟動(dòng)一個(gè)進(jìn)程 @Fork(1) //?定義類(lèi)實(shí)例的生命周期,Scope.Benchmark:所有測(cè)試線程共享一個(gè)實(shí)例,用于測(cè)試有狀態(tài)實(shí)例在多線程共享下的性能 @State(value?=?Scope.Benchmark) //?統(tǒng)計(jì)結(jié)果的時(shí)間單元 @OutputTimeUnit(TimeUnit.NANOSECONDS) public?class?JmhTest?{@Param(value?=?{"10",?"50",?"100"})private?int?length;public?static?void?main(String[]?args)?throws?RunnerException?{Options?opt?=?new?OptionsBuilder().include(JmhTest.class.getSimpleName()).result("result.json").resultFormat(ResultFormatType.JSON).build();new?Runner(opt).run();}@Benchmarkpublic?void?testStringBufferAdd(Blackhole?blackhole)?{StringBuffer?sb?=?new?StringBuffer();for?(int?i?=?0;?i?<?length;?i++)?{sb.append(i);}blackhole.consume(sb.toString());}@Benchmarkpublic?void?testStringBuilderAdd(Blackhole?blackhole)?{StringBuilder?sb?=?new?StringBuilder();for?(int?i?=?0;?i?<?length;?i++)?{sb.append(i);}blackhole.consume(sb.toString());} }

上面介紹概念時(shí)已經(jīng)提到Benchmark為基準(zhǔn)測(cè)試,在使用中只需對(duì)要測(cè)試的方法添加@Benchmark注解即可。而在測(cè)試類(lèi)JmhTest指定測(cè)試的預(yù)熱、線程、測(cè)試維度等信息。

main方法中通過(guò)OptionsBuilder構(gòu)造測(cè)試配置對(duì)象Options,并傳入Runner,啟動(dòng)測(cè)試。這里指定測(cè)試結(jié)果為json格式,同時(shí)會(huì)將結(jié)果存儲(chǔ)在result.json文件當(dāng)中。

執(zhí)行測(cè)試

執(zhí)行main方法,控制臺(tái)首先會(huì)打印出如下信息:

#?JMH?version:?1.27 #?VM?version:?JDK?1.8.0_271,?Java?HotSpot(TM)?64-Bit?Server?VM,?25.271-b09 #?VM?invoker:?/Library/Java/JavaVirtualMachines/jdk1.8.0_271.jdk/Contents/Home/jre/bin/java #?VM?options:?-javaagent:/Applications/IntelliJ?IDEA.app/Contents/lib/idea_rt.jar=56800:/Applications/IntelliJ?IDEA.app/Contents/bin?-Dfile.encoding=UTF-8 #?JMH?blackhole?mode:?full?blackhole?+?dont-inline?hint #?Warmup:?3?iterations,?1?s?each #?Measurement:?3?iterations,?4?s?each #?Timeout:?10?min?per?iteration #?Threads:?1?thread,?will?synchronize?iterations #?Benchmark?mode:?Average?time,?time/op #?Benchmark:?com.choupangxia.strings.JmhTest.testStringBufferAdd #?Parameters:?(length?=?10)

這些信息主要用來(lái)展示測(cè)試的基本信息,包括jdk、JVM、預(yù)熱配置、執(zhí)行輪次、執(zhí)行時(shí)間、執(zhí)行線程、測(cè)試的統(tǒng)計(jì)單位等。

#?Warmup?Iteration???1:?76.124?ns/op #?Warmup?Iteration???2:?77.703?ns/op #?Warmup?Iteration???3:?249.515?ns/op

這是對(duì)待測(cè)試方法的預(yù)熱處理,這部分不會(huì)記入測(cè)試結(jié)果。預(yù)熱主要讓JVM對(duì)被測(cè)代碼進(jìn)行足夠多的優(yōu)化,比如JIT編譯器的優(yōu)化。

Iteration???1:?921.191?ns/op Iteration???2:?897.729?ns/op Iteration???3:?890.245?ns/opResult?"com.choupangxia.strings.JmhTest.testStringBuilderAdd":903.055?±(99.9%)?294.557?ns/op?[Average](min,?avg,?max)?=?(890.245,?903.055,?921.191),?stdev?=?16.146CI?(99.9%):?[608.498,?1197.612]?(assumes?normal?distribution)

顯示每次(共3次)迭代執(zhí)行速率,最后進(jìn)行統(tǒng)計(jì)。這里是對(duì)testStringBuilderAdd方法執(zhí)行l(wèi)ength為100的測(cè)試,通過(guò) (min, avg, max) 三項(xiàng)可以看出最小時(shí)間、平均時(shí)間、最大時(shí)間的值,單位為ns。stdev顯示的是誤差時(shí)間。

通常情況下,我們只用看最后的結(jié)果即可:

Benchmark?????????????????????(length)??Mode??Cnt?????Score??????Error??Units JmhTest.testStringBufferAdd???????????????10??avgt????3????92.599?±??105.019??ns/op JmhTest.testStringBufferAdd???????????????50??avgt????3???582.974?±??580.536??ns/op JmhTest.testStringBufferAdd??????????????100??avgt????3??1131.460?±?1109.380??ns/op JmhTest.testStringBuilderAdd????????10??avgt????3????76.072?±????2.824??ns/op JmhTest.testStringBuilderAdd????????50??avgt????3???450.325?±???14.271??ns/op JmhTest.testStringBuilderAdd???????100??avgt????3???903.055?±??294.557??ns/op

看到上述結(jié)果我們可能會(huì)很吃驚,我們知道StringBuffer要比StringBuilder的性能低一些,但結(jié)果發(fā)現(xiàn)它們的之間的差別并不是很大。這是因?yàn)镴IT編譯器進(jìn)行了優(yōu)化,比如當(dāng)JVM發(fā)現(xiàn)在測(cè)試當(dāng)中StringBuffer并沒(méi)有發(fā)生逃逸,于是就進(jìn)行了鎖消除操作。

常用注解

下面對(duì)JHM當(dāng)中常用的注解進(jìn)行說(shuō)明,以便大家可以更精確的使用。

@BenchmarkMode

配置Mode選項(xiàng),作用于類(lèi)或者方法上,其value屬性為Mode數(shù)組,可同時(shí)支持多種Mode,如:@BenchmarkMode({Mode.SampleTime, Mode.AverageTime}),也可設(shè)為Mode.All,即全部執(zhí)行一遍。

org.openjdk.jmh.annotations.Mode為枚舉類(lèi),對(duì)應(yīng)的源代碼如下:

public?enum?Mode?{Throughput("thrpt",?"Throughput,?ops/time"),AverageTime("avgt",?"Average?time,?time/op"),SampleTime("sample",?"Sampling?time"),SingleShotTime("ss",?"Single?shot?invocation?time"),All("all",?"All?benchmark?modes");//?省略其他內(nèi)容 }

不同模式之間,測(cè)量的維度或測(cè)量的方式不同。目前JMH共有四種模式:

  • Throughput:整體吞吐量,例如“1秒內(nèi)可以執(zhí)行多少次調(diào)用”,單位為ops/time;

  • AverageTime:調(diào)用的平均時(shí)間,例如“每次調(diào)用平均耗時(shí)xxx毫秒”,單位為time/op;

  • SampleTime:隨機(jī)取樣,最后輸出取樣結(jié)果的分布,,例如“99%的調(diào)用在xxx毫秒以?xún)?nèi),99.99%的調(diào)用在xxx毫秒以?xún)?nèi)”;

  • SingleShotTime:以上模式都是默認(rèn)一次iteration是1s,只有SingleShotTime是只運(yùn)行一次。往往同時(shí)把warmup次數(shù)設(shè)為0,用于測(cè)試?yán)鋯?dòng)時(shí)的性能;

  • All:上面的所有模式都執(zhí)行一次;

@Warmup

在執(zhí)行@Benchmark之前進(jìn)行預(yù)熱操作,確保測(cè)試的準(zhǔn)確性,可用于類(lèi)或者方法上。默認(rèn)是每次運(yùn)行1秒,運(yùn)行10次。

其中@Warmup有以下屬性:

  • iterations:預(yù)熱的次數(shù);Iteration是JMH進(jìn)行測(cè)試的最小單位,在大部分模式下,一次iteration代表的是一秒,JMH會(huì)在這一秒內(nèi)不斷調(diào)用需要benchmark的方法,然后根據(jù)模式對(duì)其采樣,計(jì)算吞吐量,計(jì)算平均執(zhí)行時(shí)間等。

  • time:每次預(yù)熱的時(shí)間;

  • timeUnit:時(shí)間的單位,默認(rèn)秒;

  • batchSize:批處理大小,每次操作調(diào)用幾次方法;

JIT在執(zhí)行的過(guò)程中會(huì)將熱點(diǎn)代碼編譯為機(jī)器碼,并進(jìn)行各種優(yōu)化,從而提高執(zhí)行效率。預(yù)熱的主要目的是讓JVM的JIT機(jī)制生效,讓結(jié)果更接近真實(shí)效果。

@State

類(lèi)注解,JMH測(cè)試類(lèi)必須使用@State注解,不然會(huì)提示無(wú)法運(yùn)行。

State定義了一個(gè)類(lèi)實(shí)例的生命周期(作用范圍),可以類(lèi)比Spring Bean的Scope。因?yàn)楹芏郻enchmark會(huì)需要一些表示狀態(tài)的類(lèi),JMH會(huì)根據(jù)scope來(lái)進(jìn)行實(shí)例化和共享操作。

@State可以被繼承使用,如果父類(lèi)定義了該注解,子類(lèi)則無(wú)需定義。

由于JMH允許多線程同時(shí)執(zhí)行測(cè)試,不同的選項(xiàng)含義如下:

  • Scope.Thread:默認(rèn)的State,該狀態(tài)為每個(gè)線程獨(dú)享,每個(gè)測(cè)試線程分配一個(gè)實(shí)例;

  • Scope.Benchmark:該狀態(tài)在所有線程間共享,所有測(cè)試線程共享一個(gè)實(shí)例,用于測(cè)試有狀態(tài)實(shí)例在多線程共享下的性能;

  • Scope.Group:該狀態(tài)為同一個(gè)組里面所有線程共享。

@OutputTimeUnit

benchmark統(tǒng)計(jì)結(jié)果所使用的時(shí)間單位,可用于類(lèi)或者方法注解,使用java.util.concurrent.TimeUnit中的標(biāo)準(zhǔn)時(shí)間單位。

@Measurement

度量,其實(shí)就是實(shí)際調(diào)用方法所需要配置的一些基本測(cè)試參數(shù),可用于類(lèi)或者方法上。配置屬性項(xiàng)目和作用與@Warmup相同。

一般比較重的程序可以進(jìn)行大量的測(cè)試,放到服務(wù)器上運(yùn)行。在性能對(duì)比時(shí),采用默認(rèn)1秒即可,如果用jvisualvm做性能監(jiān)控,可以指定一個(gè)較長(zhǎng)時(shí)間運(yùn)行。

@Threads

每個(gè)進(jìn)程中同時(shí)起多少個(gè)線程執(zhí)行,可用于類(lèi)或者方法上。默認(rèn)值是Runtime.getRuntime().availableProcessors(),根據(jù)具體情況選擇,一般為cpu乘以2。

@Fork

代表啟動(dòng)多個(gè)單獨(dú)的進(jìn)程分別測(cè)試每個(gè)方法,可用于類(lèi)或者方法上。如果fork數(shù)是2的話,則JMH會(huì)fork出兩個(gè)進(jìn)程來(lái)進(jìn)行測(cè)試。

JVM因?yàn)槭褂昧藀rofile-guided optimization而“臭名昭著”,這對(duì)于微基準(zhǔn)測(cè)試來(lái)說(shuō)十分不友好,因?yàn)椴煌瑴y(cè)試方法的profile混雜在一起,“互相傷害”彼此的測(cè)試結(jié)果。對(duì)于每個(gè)@Benchmark方法使用一個(gè)獨(dú)立的進(jìn)程可以解決這個(gè)問(wèn)題,這也是JMH的默認(rèn)選項(xiàng)。注意不要設(shè)置為0,設(shè)置為n則會(huì)啟動(dòng)n個(gè)進(jìn)程執(zhí)行測(cè)試(似乎也沒(méi)有太大意義)。fork選項(xiàng)也可以通過(guò)方法注解以及啟動(dòng)參數(shù)來(lái)設(shè)置。

@Param

屬性級(jí)注解,指定某項(xiàng)參數(shù)的多種情況,特別適合用來(lái)測(cè)試一個(gè)函數(shù)在不同的參數(shù)輸入的情況下的性能,只能作用在字段上,使用該注解必須定義@State注解。

@Param注解接收一個(gè)String數(shù)組,在@Setup方法執(zhí)行前轉(zhuǎn)化為對(duì)應(yīng)的數(shù)據(jù)類(lèi)型。多個(gè)@Param注解的成員之間是乘積關(guān)系,譬如有兩個(gè)用@Param注解的字段,第一個(gè)有5個(gè)值,第二個(gè)字段有2個(gè)值,那么每個(gè)測(cè)試方法會(huì)跑5*2=10次。

@Benchmark

方法注解,表示該方法是需要進(jìn)行benchmark的對(duì)象,用法和JUnit的@Test類(lèi)似。

@Setup

方法注解,這個(gè)注解的作用就是我們需要在測(cè)試之前進(jìn)行一些準(zhǔn)備工作,比如對(duì)一些數(shù)據(jù)的初始化之類(lèi)的。

@TearDown

方法注解,與@Setup相對(duì)的,會(huì)在所有benchmark執(zhí)行結(jié)束以后執(zhí)行,比如關(guān)閉線程池,數(shù)據(jù)庫(kù)連接等的,主要用于資源的回收等。

Threads

每個(gè)fork進(jìn)程使用多少個(gè)線程去執(zhí)行測(cè)試方法,默認(rèn)值是Runtime.getRuntime().availableProcessors()。

@Group

方法注解,可以把多個(gè)benchmark定義為同一個(gè)group,則它們會(huì)被同時(shí)執(zhí)行,譬如用來(lái)模擬生產(chǎn)者-消費(fèi)者讀寫(xiě)速度不一致情況下的表現(xiàn)。

@Level

用于控制@Setup,@TearDown的調(diào)用時(shí)機(jī),默認(rèn)是Level.Trial。

  • Trial:每個(gè)benchmark方法前后;

  • Iteration:每個(gè)benchmark方法每次迭代前后;

  • Invocation:每個(gè)benchmark方法每次調(diào)用前后,謹(jǐn)慎使用,需留意javadoc注釋;

JMH注意事項(xiàng)

無(wú)用代碼消除(Dead Code Elimination)

現(xiàn)代編譯器是十分聰明的,它們會(huì)對(duì)代碼進(jìn)行推導(dǎo)分析,判定哪些代碼是無(wú)用的然后進(jìn)行去除,這種行為對(duì)微基準(zhǔn)測(cè)試是致命的,它會(huì)使你無(wú)法準(zhǔn)確測(cè)試出你的方法性能。

JMH本身已經(jīng)對(duì)這種情況做了處理,要記住:1.永遠(yuǎn)不要寫(xiě)void方法;2.在方法結(jié)束返回計(jì)算結(jié)果。有時(shí)候如果需要返回多于一個(gè)結(jié)果,可以考慮自行合并計(jì)算結(jié)果,或者使用JMH提供的BlackHole對(duì)象:

/**?This?demonstrates?Option?A:**?Merge?multiple?results?into?one?and?return?it.*?This?is?OK?when?is?computation?is?relatively?heavyweight,?and?merging*?the?results?does?not?offset?the?results?much.*/ @Benchmark public?double?measureRight_1()?{return?Math.log(x1)?+?Math.log(x2); } /**?This?demonstrates?Option?B:**?Use?explicit?Blackhole?objects,?and?sink?the?values?there.*?(Background:?Blackhole?is?just?another?@State?object,?bundled?with?JMH).*/ @Benchmark public?void?measureRight_2(Blackhole?bh)?{bh.consume(Math.log(x1));bh.consume(Math.log(x2)); }

再比如下面代碼:

@Benchmark public?void?testStringAdd(Blackhole?blackhole)?{String?a?=?"";for?(int?i?=?0;?i?<?length;?i++)?{a?+=?i;} }

JVM可能會(huì)認(rèn)為變量a從來(lái)沒(méi)有使用過(guò),從而進(jìn)行優(yōu)化把整個(gè)方法內(nèi)部代碼移除掉,這就會(huì)影響測(cè)試結(jié)果。

JMH提供了兩種方式避免這種問(wèn)題,一種是將這個(gè)變量作為方法返回值return a,一種是通過(guò)Blackhole的consume來(lái)避免JIT 的優(yōu)化消除。

常量折疊(Constant Folding)

常量折疊是一種現(xiàn)代編譯器優(yōu)化策略,例如,i = 320 * 200 * 32,多數(shù)的現(xiàn)代編譯器不會(huì)真的產(chǎn)生兩個(gè)乘法的指令再將結(jié)果儲(chǔ)存下來(lái),取而代之的,它們會(huì)辨識(shí)出語(yǔ)句的結(jié)構(gòu),并在編譯時(shí)期將數(shù)值計(jì)算出來(lái)(i = 2,048,000)。

在微基準(zhǔn)測(cè)試中,如果你的計(jì)算輸入是可預(yù)測(cè)的,也不是一個(gè)@State實(shí)例變量,那么很可能會(huì)被JIT給優(yōu)化掉。對(duì)此,JMH的建議是:1.永遠(yuǎn)從@State實(shí)例中讀取你的方法輸入;2.返回你的計(jì)算結(jié)果;3.或者考慮使用BlackHole對(duì)象;

見(jiàn)如下官方例子:

@State(Scope.Thread) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) public?class?JMHSample_10_ConstantFold?{private?double?x?=?Math.PI;private?final?double?wrongX?=?Math.PI;@Benchmarkpublic?double?baseline()?{//?simply?return?the?value,?this?is?a?baselinereturn?Math.PI;}@Benchmarkpublic?double?measureWrong_1()?{//?This?is?wrong:?the?source?is?predictable,?and?computation?is?foldable.return?Math.log(Math.PI);}@Benchmarkpublic?double?measureWrong_2()?{//?This?is?wrong:?the?source?is?predictable,?and?computation?is?foldable.return?Math.log(wrongX);}@Benchmarkpublic?double?measureRight()?{//?This?is?correct:?the?source?is?not?predictable.return?Math.log(x);}public?static?void?main(String[]?args)?throws?RunnerException?{Options?opt?=?new?OptionsBuilder().include(JMHSample_10_ConstantFold.class.getSimpleName()).warmupIterations(5).measurementIterations(5).forks(1).build();new?Runner(opt).run();} }

循環(huán)展開(kāi)(Loop Unwinding)

循環(huán)展開(kāi)最常用來(lái)降低循環(huán)開(kāi)銷(xiāo),為具有多個(gè)功能單元的處理器提供指令級(jí)并行。也有利于指令流水線的調(diào)度。例如:

for?(i?=?1;?i?<=?60;?i++)?a[i]?=?a[i]?*?b?+?c;

可以展開(kāi)成:

for?(i?=?1;?i?<=?60;?i+=3){a[i]?=?a[i]?*?b?+?c;a[i+1]?=?a[i+1]?*?b?+?c;a[i+2]?=?a[i+2]?*?b?+?c; }

由于編譯器可能會(huì)對(duì)你的代碼進(jìn)行循環(huán)展開(kāi),因此JMH建議不要在你的測(cè)試方法中寫(xiě)任何循環(huán)。如果確實(shí)需要執(zhí)行循環(huán)計(jì)算,可以結(jié)合@BenchmarkMode(Mode.SingleShotTime)和@Measurement(batchSize = N)來(lái)達(dá)到同樣的效果。參考如下例子:

/**?Suppose?we?want?to?measure?how?much?it?takes?to?sum?two?integers:*/ int?x?=?1; int?y?=?2; /**?This?is?what?you?do?with?JMH.*/ @Benchmark @OperationsPerInvocation(100) public?int?measureRight()?{return?(x?+?y); }

JMH可視化

在示例的main方法中指定了生成測(cè)試結(jié)果的輸出文件result.json,其中的內(nèi)容就是控制臺(tái)輸出的相關(guān)內(nèi)容以json格式存儲(chǔ)。

針對(duì)json格式的內(nèi)容,可以在其他網(wǎng)站上以圖表的形式可視化展示。

對(duì)應(yīng)網(wǎng)站,JMH Visual Chart(http://deepoove.com/jmh-visual-chart/)、JMH Visualizer(https://jmh.morethan.io/)。

展示效果如下圖:

img

生成jar包執(zhí)行

對(duì)于大型的測(cè)試,一般會(huì)放在Linux服務(wù)器里去執(zhí)行。JMH官方提供了生成jar包的方式來(lái)執(zhí)行,在maven里增加如下插件:

<plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>2.4.1</version><executions><execution><phase>package</phase><goals><goal>shade</goal></goals><configuration><finalName>jmh-demo</finalName><transformers><transformerimplementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"><mainClass>org.openjdk.jmh.Main</mainClass></transformer></transformers></configuration></execution></executions></plugin> </plugins>

執(zhí)行maven的命令生成可執(zhí)行jar包,并執(zhí)行:

mvn?clean?package java?-jar?target/jmh-demo.jar?JmhTest

總結(jié)

一篇文章幾乎涵蓋了JMH各方面的知識(shí)點(diǎn),如果實(shí)踐中還沒(méi)運(yùn)用,趕緊用起來(lái)吧,你的專(zhuān)業(yè)水平將又提升那么一點(diǎn)。當(dāng)然,也可以收藏起來(lái),以備不時(shí)不需。

參考文章:

https://www.zhihu.com/question/276455629/answer/1259967560 https://www.cnblogs.com/silyvin/p/11736696.html https://blog.csdn.net/wangxuelei036/article/details/105240522 https://www.cnblogs.com/xiang--liu/p/9710143.html

往期推薦

6種快速統(tǒng)計(jì)代碼執(zhí)行時(shí)間的方法,真香!(史上最全)


Oracle官方推薦的性能測(cè)試工具!簡(jiǎn)單、精準(zhǔn)又直觀!


鏈表竟然比數(shù)組慢了1000多倍?(動(dòng)圖+性能評(píng)測(cè))


關(guān)注我,每天陪你進(jìn)步一點(diǎn)點(diǎn)!

總結(jié)

以上是生活随笔為你收集整理的不要再用main方法测试代码性能了,用这款JDK自带工具的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美aa大片 | 91高清无打码 | 色呦呦视频在线 | 久久久久人 | 国产一区二区三区高清视频 | 国产一区在线不卡 | 黄色com| 富婆如狼似虎找黑人老外 | 黄站在线观看 | 人妻少妇被粗大爽9797pw | 91精产国品一二三区在线观看 | 波多野结衣福利 | 特黄一级毛片 | v天堂在线| 人妻丰满熟妇无码区免费 | 国产成人亚洲一区二区 | 日韩一区二区三区三四区视频在线观看 | 欧洲黄色网 | 无码精品国产一区二区三区免费 | 少妇闺蜜换浪荡h肉辣文 | 国产原创在线观看 | 1024手机看片国产 | 欧美成人91 | 日韩一卡| 中国少妇高潮 | 永久免费不卡在线观看黄网站 | 制服师生在线 | 欧美伦理在线观看 | 精品在线观看免费 | 久久久久久久偷拍 | 伊人影院在线观看 | 欧美伦理一区二区三区 | 91成人在线观看高潮 | 伊人夜色 | 久操视频在线播放 | 超碰在线免费播放 | 白又丰满大屁股bbbbb | 波多野结衣中文字幕一区二区 | 二级黄色大片 | 日日噜噜夜夜狠狠久久波多野 | 日韩国产小视频 | 日鲁鲁| 成年人黄色片网站 | 久99精品 | 日本美女上床 | 国产免费av一区 | 色www.| 亚洲午夜精品久久久久久app | www麻豆视频 | 九九激情视频 | 日韩精品一区二区三区中文在线 | 99精品国产99久久久久久97 | 高清日韩一区二区 | 超碰人人人人人人 | 三级黄片毛片 | 人人妻人人澡人人爽精品日本 | 国产九九九 | 欧美理论视频 | 国产精品av网站 | 性高潮影院 | 亚洲精品乱码久久久久久蜜桃欧美 | 亚洲精品99999| 国产一级在线播放 | 91美女诱惑 | 欧美性猛交99久久久久99按摩 | 日本特黄特色aaa大片免费 | 中文字幕一区二区人妻痴汉电车 | 精品777| 亚洲精品一区二区在线 | 日韩欧美日韩 | 国产精九九网站漫画 | 日本a级一区 | 夜间福利网站 | 日韩欧美成人一区二区三区 | 全肉的吸乳文 | 欧美三级三级三级爽爽爽 | 特级西西人体 | www.黄色网 | 欧美啪视频 | 国产精品国产三级国产专播品爱网 | 草莓巧克力香氛动漫的观看方法 | 久久黄色录像 | av鲁丝一区鲁丝二区鲁丝 | 天堂在线精品视频 | 日韩欧洲亚洲AV无码精品 | 国产精品 欧美精品 | 天堂中文字幕免费一区 | 黄色日韩视频 | 四虎影院一区二区 | 91精品视频在线看 | 色中色在线视频 | 高潮一区二区三区乱码 | 天天干夜夜爽 | 美女在线播放 | 国产欧美日韩视频在线观看 | 免费黄色网址观看 | 日日摸夜夜添狠狠添欧美 | 牛牛影视av| 最新国产精品视频 |