0Pricing
Java Academy · レッスン

デッドコード削除の回避

Blackhole と状態を扱います。

「デッドコード削除の回避」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

デッドコード除去の回避

マイクロベンチマークで最大の落とし穴はデッドコード除去(DCE)です。JIT が結果をまったく使わないと判断すると、計算を削除してしまいます。その場合、ベンチマークは何も測定していません。JMH には、これを防ぐ 2 つの方法があります。値を返すことと、Blackhole を使うことです。

DCE の落とし穴

このループは平方根を 100 万回計算しますが、結果をまったく使っていません。賢いコンパイラなら、ループ全体を削除できます。

public class Main {
    public static void main(String[] args) {
        long t = System.nanoTime();
        for (int i = 0; i < 1_000_000; i++) {
            double ignored = Math.sqrt(i); // result thrown away
        }
        System.out.println("ns: " + (System.nanoTime() - t));
    }
}

修正 1: 結果を返す

最も簡単な対策は、@Benchmark メソッドから計算結果を返すことです。JMH は返されたすべての値を消費するため、JVM はその値が不要だと判断できません。

import org.openjdk.jmh.annotations.Benchmark;

public class Bench {
    @Benchmark
    public double sqrt() {
        return Math.sqrt(42.0); // returned -> consumed by JMH
    }
}

修正 2: Blackhole

ベンチマークが複数の値を生成する場合や、1 つの値を返せない場合は、Blackhole を注入して consume(...) を呼び出します。Blackhole は、実際の処理にかかるコストなしに、各値が使われていると JIT に認識させます。

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.infra.Blackhole;

public class Bench {
    @Benchmark
    public void manyValues(Blackhole bh) {
        for (int i = 0; i < 100; i++) {
            bh.consume(Math.sqrt(i));
        }
    }
}

@State オブジェクト

@State クラスは、オプティマイザーから不透明に見える入力を保持し、定数畳み込みを防ぎます。JMH がこのクラスをインスタンス化して、ベンチマークに渡します。スコープには Thread、Benchmark(共有)、Group を指定できます。

import org.openjdk.jmh.annotations.*;

public class Bench {
    @State(Scope.Thread)
    public static class Data {
        public int x = 21;
    }

    @Benchmark
    public int multiply(Data d) {
        return d.x * 2; // d.x is not a compile-time constant
    }
}

@Setup と @TearDown

@State クラス内で、@Setup が付いたメソッドは測定前に実行され、@TearDown が付いたメソッドは測定後に実行されます。Level で実行頻度を制御します。指定できるのは Trial(1 回)、Iteration、Invocation です。

import org.openjdk.jmh.annotations.*;

@State(Scope.Thread)
public class Data {
    int[] arr;
    @Setup(Level.Trial)
    public void init() {
        arr = new int[1000];
        for (int i = 0; i < arr.length; i++) arr[i] = i;
    }
}

定数入力を避ける

テスト対象メソッドにリテラル定数を決して渡さないでください。Math.sqrt(2.0)は定数に畳み込まれる可能性がありますが、Math.sqrt(state.value)は畳み込まれません。入力は必ず@Stateフィールドから取得してください。

複数の値を返す

ベンチマークで自然に2つの結果が生成される場合は、一方を返し、もう一方をBlackholeで消費するか、結果を組み合わせることができます。どちらか一方でも消費しないままにすると、DCEの抜け道が再び生じます。

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.infra.Blackhole;

public class Bench {
    @Benchmark
    public int twoResults(Blackhole bh) {
        int a = 3 * 7;
        int b = 5 + 9;
        bh.consume(b);
        return a;
    }
}

Blackholeのオーバーヘッド

Blackholeは非常に低コストで、Blackhole自体も最適化されにくいように設計されていますが、完全に無料ではありません。極めて高速な処理では単一の値を返す方法を優先し、ループや複数の値を扱う場合にBlackholeを使用してください。

数値の妥当性を確認する

ベンチマークが実際の処理としては不可能なほど短い時間(ナノ秒未満)を報告した場合は、DCEまたは定数畳み込みを疑ってください。結果を返すか消費していること、入力が@Stateから取得されていることを再確認してください。

総仕上げ

堅牢なベンチマークでは、@Stateオブジェクトから入力を読み取り、処理を実行したうえで、結果をreturnするかBlackhole.consumeで消費します。この3つの習慣により、DCEや定数畳み込みによって測定結果が歪められることを防げます。

クイックチェック

デッドコード除去を防ぐ方法についての理解度を確認してください。

振り返り

ベンチマークを正確に保つ方法を学びました。

  • デッドコード除去は、使用されていない計算を削除します。
  • JMHが消費できるように、単一の結果を返します。
  • ループや複数の値にはBlackhole.consumeを使用します。
  • @Stateオブジェクトによって入力を不透明に保ち、定数畳み込みを防ぎます。
  • @Setup / @TearDownによって、指定したLevelで状態の準備と後片付けを行います。

よくある質問

「デッドコード削除の回避」レッスンは無料ですか?

はい。「デッドコード削除の回避」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「デッドコード削除の回避」で何を学びますか?

Blackhole と状態を扱います。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「デッドコード削除の回避」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. JMH を使う理由
  2. ベンチマークの記述
  3. ウォームアップと反復
  4. デッドコード削除の回避
← Java Academyに戻る