Java函數(shù)性能分析

Java函數(shù)性能分析

測(cè)試函數(shù)性能,比較兩個(gè)函數(shù)的執(zhí)行效率差異是開發(fā)時(shí)經(jīng)常面臨的場(chǎng)景,像Go官方提供了 benchmark 工具,那么Java呢?

Java也提供了一款官方的微基準(zhǔn)測(cè)試工具: JMH !


  • JMH 怎么使用?
    1. 引入 maven 依賴

      <dependency>
          <groupId>org.openjdk.jmh</groupId>
          <artifactId>jmh-core</artifactId>
          <version>1.23</version>
      </dependency>
      <dependency>
          <groupId>org.openjdk.jmh</groupId>
          <artifactId>jmh-generator-annprocess</artifactId>
          <version>1.23</version>
          <scope>provided</scope>
      </dependency>
      
    2. 函數(shù)添加注解:@Benchmark

    3. 函數(shù)或所在類添加注解:

      • @BenchmarkMode 用來(lái)配置 Mode 選項(xiàng)

        • Throughput:整體吞吐量,每秒執(zhí)行了多少次調(diào)用,單位為 ops/time
        • AverageTime:用的平均時(shí)間,每次操作的平均時(shí)間,單位為 time/op
        • SampleTime:隨機(jī)取樣,最后輸出取樣結(jié)果的分布
        • SingleShotTime:只運(yùn)行一次,往往同時(shí)把 Warmup 次數(shù)設(shè)為 0,用于測(cè)試?yán)鋯?dòng)時(shí)的性能
        • All:上面的所有模式都執(zhí)行一次
      • @Warmup 預(yù)熱所需要配置的一些基本測(cè)試參數(shù)

        • iterations:預(yù)熱的次數(shù)
        • time:每次預(yù)熱的時(shí)間
        • timeUnit:時(shí)間的單位,默認(rèn)秒
        • batchSize:批處理大小,每次操作調(diào)用幾次方法
      • @Measurement 實(shí)際調(diào)用方法所需要配置的一些基本測(cè)試參數(shù)

      • @Threads 每個(gè)進(jìn)程中的測(cè)試線程

      • @Fork 進(jìn)行 fork 的次數(shù)。如果 fork 數(shù)是 2 的話,則 JMH 會(huì) fork 出兩個(gè)進(jìn)程來(lái)進(jìn)行測(cè)試。

      • @State 可以指定一個(gè)對(duì)象的作用范圍。JMH 根據(jù) scope 來(lái)進(jìn)行實(shí)例化和共享操作。

        • Scope.Benchmark:所有測(cè)試線程共享一個(gè)實(shí)例,測(cè)試有狀態(tài)實(shí)例在多線程共享下的性能
        • Scope.Group:同一個(gè)線程在同一個(gè) group 里共享實(shí)例
        • Scope.Thread:默認(rèn)的 State,每個(gè)測(cè)試線程分配一個(gè)實(shí)例
      • @OutputTimeUnit 為統(tǒng)計(jì)結(jié)果的時(shí)間單位

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

  • 簡(jiǎn)單的代碼樣例參考?
    package org.example;
    
    import org.openjdk.jmh.annotations.*;
    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;
    
    import java.util.concurrent.TimeUnit;
    
    @BenchmarkMode(Mode.AverageTime)
    @State(Scope.Thread)
    @Fork(1)
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    @Warmup(iterations = 3)
    @Measurement(iterations = 5)
    public class JmhTest {
        String string = "";
        StringBuilder stringBuilder = new StringBuilder();
    
        @Benchmark
        public String stringAdd() {
            for (int i = 0; i < 1000; i++) {
                string = string + i;
            }
            return string;
        }
    
        @Benchmark
        public String stringBuilderAppend() {
            for (int i = 0; i < 1000; i++) {
                stringBuilder.append(i);
            }
            return stringBuilder.toString();
        }
    
        public static void main(String[] args) throws RunnerException {
            Options opt = new OptionsBuilder()
                    .include(JmhTest.class.getSimpleName())
                    .build();
            new Runner(opt).run();
        }
    }
    
    

使用JMH時(shí)需要注意

測(cè)試代碼注意避免JVM的優(yōu)化,導(dǎo)致JMH分析結(jié)果對(duì)你出現(xiàn)誤判。JMH運(yùn)行統(tǒng)計(jì)是基于JVM運(yùn)行,你的代碼在JVM運(yùn)行前會(huì)被JIT優(yōu)化。包括但不限于:

  • 死碼消除
    @Benchmark
    public void testStringAdd(Blackhole blackhole) {
        String a = "";
        for (int i = 0; i < length; i++) {
            a += i;
        }
    }
    // JVM 可能會(huì)認(rèn)為變量 a 從來(lái)沒有使用過(guò),從而進(jìn)行優(yōu)化把整個(gè)方法內(nèi)部代碼移除掉,這就會(huì)影響測(cè)試結(jié)果。
    // MH 提供了兩種方式避免這種問題,一種是將這個(gè)變量作為方法返回值 return a,一種是通過(guò) Blackhole 的 consume 來(lái)避免 JIT 的優(yōu)化消除。
    
  • 常量折疊
  • 常量傳播
  • .....(更多的陷阱demo參考: https://github.com/lexburner/JMH-samples)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容