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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 官方性能测试工具 JMH 简单入门

發布時間:2025/3/11 java 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 官方性能测试工具 JMH 简单入门 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是 JMH

JMH 是 Java Microbenchmark Harness 的縮寫。中文意思大致是 “JAVA 微基準測試套件”。首先先明白什么是“基準測試”。百度百科給的定義如下:

基準測試是指通過設計科學的測試方法、測試工具和測試系統,實現對一類測試對象的某項性能指標進行定量的和可對比的測試。

可以簡單的類比成我們電腦常用的魯大師,或者手機常用的跑分軟件安兔兔之類的性能檢測軟件。都是按一定的基準或者在特定條件下去測試某一對象的的性能,比如顯卡、IO、CPU之類的。

為什么要使用 JMH

基準測試的特質有如下幾種:

①、可重復性:可進行重復性的測試,這樣做有利于比較每次的測試結果,得到性能結果的長期變化趨勢,為系統調優和上線前的容量規劃做參考。

②、可觀測性:通過全方位的監控(包括測試開始到結束,執行機、服務器、數據庫),及時了解和分析測試過程發生了什么。

③、可展示性:相關人員可以直觀明了的了解測試結果(web界面、儀表盤、折線圖樹狀圖等形式)。

④、真實性:測試的結果反映了客戶體驗到的真實的情況(真實準確的業務場景+與生產一致的配置+合理正確的測試方法)。

⑤、可執行性:相關人員可以快速的進行測試驗證修改調優(可定位可分析)。

可見要做一次符合特質的基準測試,是很繁瑣也很困難的。外界因素很容易影響到最終的測試結果。特別對于 JAVA的基準測試。


有些文章會告訴我們 JAVA是 C++編寫的,一般來說 JAVA編寫的程序不太可能比 C++編寫的代碼運行效率更好。但是JAVA在某些場景的確要比 C++運行的更高效。不要覺得天方夜譚。其實 JVM隨著這些年的發展已經變得很智能,它會在運行期間不斷的去優化。


這對于我們程序來說是好事,但是對于性能測試就頭疼的。你運行的次數與時間不同可能獲得的結果也不同,很難獲得一個比較穩定的結果。對于這種情況,有一個解決辦法就是大量的重復調用,并且在真正測試前還要進行一定的預熱,使結果盡可能的準確。

除了這些,對于結果我們還需要一個很好的展示,可以讓我們通過這些展示結果判斷性能的好壞。

而這些JMH都有!?

如何使用 JMH

下面我們以字符串拼接的幾種方法為例子使用JMH做基準測試。

1. 導入依賴

JMH是 JDK9自帶的,如果你是 JDK9 之前的版本也可以通過導入 openjdk

<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>

2. 目錄結構

. ├── pom.xml └── src├── main│ └── java│ └── cn│ └── coder4j│ └── study│ └── demo│ └── jmh│ ├── benchmark│ │ └── StringConnectBenchmark.java│ └── runner│ └── StringBuilderRunner.java└── test└── java└── cn└── coder4j└── study└── demo

3. 具體代碼

  • StringBuilderRunner.java
/*** coder4j.cn* Copyright (C) 2013-2018 All Rights Reserved.*/ package cn.coder4j.study.demo.jmh.runner;import cn.coder4j.study.demo.jmh.benchmark.StringConnectBenchmark; import org.openjdk.jmh.annotations.Mode; 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;/*** @author buhao* @version StringBuilderRunner.java, v 0.1 2018-12-25 09:53 buhao*/ public class StringBuilderRunner {public static void main( String[] args ) throws RunnerException {Options opt = new OptionsBuilder()// 導入要測試的類.include(StringConnectBenchmark.class.getSimpleName())// 預熱5輪.warmupIterations(5)// 度量10輪.measurementIterations(10).mode(Mode.Throughput).forks(3).build();new Runner(opt).run();}}
  • StringConnectBenchmark.java
/*** coder4j.cn* Copyright (C) 2013-2018 All Rights Reserved.*/ package cn.coder4j.study.demo.jmh.benchmark;import org.openjdk.jmh.annotations.Benchmark;/*** @author buhao* @version StringConnectBenchmark.java, v 0.1 2018-12-25 09:29 buhao*/ public class StringConnectBenchmark {/*** 字符串拼接之 StringBuilder 基準測試*/@Benchmarkpublic void testStringBuilder() {print(new StringBuilder().append(1).append(2).append(3).toString());}/*** 字符串拼接之直接相加基準測試*/@Benchmarkpublic void testStringAdd() {print(new String()+ 1 + 2 + 3);}/*** 字符串拼接之String Concat基準測試*/@Benchmarkpublic void testStringConcat() {print(new String().concat("1").concat("2").concat("3"));}/*** 字符串拼接之 StringBuffer 基準測試*/@Benchmarkpublic void testStringBuffer() {print(new StringBuffer().append(1).append(2).append(3).toString());}/*** 字符串拼接之 StringFormat 基準測試*/@Benchmarkpublic void testStringFormat(){print(String.format("%s%s%s", 1, 2, 3));}public void print(String str) {} }

4. 運行結果

# Run progress: 93.33% complete, ETA 00:00:15 # Fork: 3 of 3 objc[12440]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/jre/bin/java (0x106a7d4c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x106af74e0). One of the two will be used. Which one is undefined. # Warmup Iteration 1: 747281.755 ops/s # Warmup Iteration 2: 924220.081 ops/s # Warmup Iteration 3: 1129741.585 ops/s # Warmup Iteration 4: 1135268.541 ops/s # Warmup Iteration 5: 1062994.936 ops/s Iteration 1: 1142834.160 ops/s Iteration 2: 1143207.472 ops/s Iteration 3: 1178363.827 ops/s Iteration 4: 1156408.897 ops/s Iteration 5: 1123123.829 ops/s Iteration 6: 1086029.992 ops/s Iteration 7: 1108795.147 ops/s Iteration 8: 1125522.731 ops/s Iteration 9: 1120021.744 ops/s Iteration 10: 1119916.181 ops/sResult "cn.coder4j.study.demo.jmh.benchmark.StringConnectBenchmark.testStringFormat":1132633.183 ±(99.9%) 16252.303 ops/s [Average](min, avg, max) = (1082146.355, 1132633.183, 1182418.648), stdev = 24325.684CI (99.9%): [1116380.879, 1148885.486] (assumes normal distribution)# Run complete. Total time: 00:03:57Benchmark Mode Cnt Score Error Units StringConnectBenchmark.testStringAdd thrpt 30 63728919.269 ± 906608.141 ops/s StringConnectBenchmark.testStringBuffer thrpt 30 112423521.098 ± 1157072.848 ops/s StringConnectBenchmark.testStringBuilder thrpt 30 110558976.274 ± 654163.111 ops/s StringConnectBenchmark.testStringConcat thrpt 30 44820009.200 ± 524305.660 ops/s StringConnectBenchmark.testStringFormat thrpt 30 1132633.183 ± 16252.303 ops/s

5. 代碼解析

  • StringBuilderRunner

這個 runner 類的作用,就是啟動基準測試。


JMH 通常有兩種方式啟動,一種就是通過命令行使用 maven 命令執行。這種適合對于大型基準測試,像那些要運行很多很多次,并且運行的時間也很長的情況下。你可以直接打個 jar包,發到服務器上,敲個命令就不用管它,過幾十分鐘、幾小時、幾天的時間再回來看結果。

但是很多情況下,我們只是想簡單測試一個小功能,沒必要還要搞臺服務器去跑。所以 JMH 還提供了一種通過 Main方法運行的方式,就如上面代碼所示。

在 Main 方法中,通過 org.openjdk.jmh.runner.Runner 類去運行 org.openjdk.jmh.runner.options.Options 實例即可。這里的重點在于 Options 對象的構建。官方提供了一個OptionsBuilder對象去構建。這個 Builder對象是流式的。它的常用方法及對應的注解形式如下:

方法名參數作用對應注解
include要運行基準測試類的簡單名稱 eg. StringConnectBenchmark指定要運行的基準測試類-
exclude不要運行基準測試類的簡單名稱 eg. StringConnectBenchmark指定不要運行的基準測試類-
warmupIterations預熱的迭代次數指定預熱的迭代次數@Warmup
warmupBatchSize預熱批量的大小指定預熱批量的大小@Warmup
warmupForks預熱模式:INDI,BULK,BULK_INDI指定預熱模式@Warmup
warmupMode預熱的模式指定預熱的模式@Warmup
warmupTime預熱的時間指定預熱的時間@Warmup
measurementIterations測試的迭代次數指定測試的迭代次數@Measurement
measurementBatchSize測試批量的大小指定測試批量的大小@Measurement
measurementTime測試的時間指定測試的時間@Measurement
mode測試模式: Throughput(吞吐量), AverageTime(平均時間),SampleTime(在測試中,隨機進行采樣執行的時間),SingleShotTime(在每次執行中計算耗時),All指定測試的模式@BenchmarkMode
  • StringConnectBenchmark


這個就是真正執行基準測試的類,這個類很像單元測試的類,每個測試方法中寫上你要執行的測試代碼。只不過這里把@Test換成了@Benchmark注解。


而加上了這個就指明這個方法是基準測試方法,當 Runner類的 Main方法運行時,它就會找這些被注解修飾的方法,再按指定的規則去進行基準測試。當然可能不同的方法有時候需要不同的規則,這個時間可以通過上面方法對應的注解形式去單獨指定某個方法的規則即可。

6. 結果解析


結果主要分成三個部分。


第一部分以 “#Warmup Iteration。。。。”這種形式的內容。這表明每次預熱迭代的結果。


另一部分以“Iteration。。。”形式內容,這表明每次基準測試迭代的結果。

最后一部分以“Result。。。”形式的內容,這就是所有迭代跑完最終的結果。第一段結果告訴了我們最大值、最小值、平均值的信息。


而最最后的表格結構的信息才是我們分析的重點,但是它輸出的結果有點錯位,剛開始我一直在糾結 Error是± 906608.141代表什么意思,google了一圈發現,Error它其實什么都沒輸出,而且 Score 是63728919.269 ± 906608.141。我用表格排板了一下,解釋如下:

BenchmarkModeCntScoreErrorUnits
基準測試執行的方法測試模式,這里是吞吐量運行多少次分數錯誤單位
StringConnectBenchmark.testStringAddthrpt3063728919.269 ± 906608.141ops/s
StringConnectBenchmark.testStringBufferthrpt30112423521.098 ± 1157072.848ops/s
StringConnectBenchmark.testStringBuilderthrpt30110558976.274 ± 654163.111ops/s
StringConnectBenchmark.testStringConcatthrpt3044820009.200 ± 524305.660ops/s
StringConnectBenchmark.testStringFormatthrpt301132633.183 ± 16252.303ops/s

結論:

StringBuffer >= StringBuilder > String直接相加 > StringConcat >> StringFormat

可見 StringBuffer 與 StringBuilder 大致性能相同,都比直接相加高幾個數量級,而且直接相加與 Concat 方法相加差不多。但是這里不管哪種都比 StringFormat高 N 個數量級。所以 String的 Format方法一定要慎用、不用、禁用!!!

作者:KiwiFly

鏈接:https://www.jianshu.com/p/c9186119f3d1

來源:簡書

更多 Java 原創文章,請關注我微信公眾號 「Java中文社群」

總結

以上是生活随笔為你收集整理的Java 官方性能测试工具 JMH 简单入门的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。