Java Academy · Lektion

Undvik eliminering av död kod

Blackhole och tillstånd.

Lektion 4 av 413 steg

Undvik eliminering av död kod är en gratis lektion i Java Academy på CoddyKit. Detta är lektion 4 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Java Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Java Academy innehåller totalt 4 lektioner.

Undvika eliminering av död kod

Den största fällan vid microbenchmarking är eliminering av död kod (DCE): om JIT kan bevisa att ett resultat aldrig används tar den bort beräkningen. Då mäter benchmarktestet ingenting. JMH ger Er två verktyg för att förhindra detta — att returnera värden och Blackhole.

DCE-fällan

Den här slingan beräknar en kvadratrot en miljon gånger men använder aldrig resultatet. En smart kompilator kan ta bort hela slingan.

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));
    }
}

Lösning 1: Returnera resultatet

Det enklaste skyddet är att returnera det beräknade värdet från metoden med @Benchmark. JMH konsumerar varje returnerat värde, så JVM kan inte bevisa att det är oanvänt.

import org.openjdk.jmh.annotations.Benchmark;

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

Lösning 2: Blackhole

När ett benchmarktest producerar flera värden eller när Ni inte kan returnera ett värde, injicerar Ni en Blackhole och anropar consume(...). Blackhole övertygar JIT om att varje värde används, utan kostnaden för ett verkligt arbete.

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));
        }
    }
}

Objekt med @State

En klass med @State innehåller indata som är ogenomskinliga för optimeraren, vilket förhindrar constant folding. JMH instansierar klassen och skickar den till ert benchmarktest. Omfattningen kan vara Thread, Benchmark (delad) eller 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 och @TearDown

I en klass med @State körs metoder som annoterats med @Setup före mätningen och @TearDown efteråt. Level styr hur ofta de körs: Trial (en gång), Iteration eller 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;
    }
}

Undvik konstanta indata

Skicka aldrig literala konstanter till metoden som testas. Math.sqrt(2.0) kan vikas till en konstant, medan Math.sqrt(state.value) inte kan det. Hämta alltid indata från ett @State-fält.

Returnera flera värden

Om ditt benchmark naturligt producerar två resultat kan du returnera det ena och konsumera det andra via en Blackhole, eller kombinera dem. Om något av resultaten lämnas okonsumerat uppstår problemet med DCE igen.

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

Blackhole är utformat för att vara extremt kostnadseffektivt och samtidigt självt motstå optimering, men det är inte helt gratis. För ultrasnabba operationer bör du helst returnera ett enda värde och använda Blackhole för loopar och fall med flera värden.

Rimlighetskontrollera dina siffror

Om ett benchmark rapporterar en orimligt kort tid (under en nanosekund för verkligt arbete) bör du misstänka DCE eller konstantvikning. Kontrollera på nytt att resultaten returneras eller konsumeras och att indatan kommer från @State.

Sätt ihop allt

Ett robust benchmark läser indata från ett @State-objekt, utför arbetet och antingen return:ar resultatet eller konsumerar det med Blackhole.consume. Med dessa tre vanor kan DCE och konstantvikning inte förvränga dina mätningar.

Snabbtest

Testa dina kunskaper om hur du förhindrar eliminering av död kod.

Sammanfattning

Du har lärt dig att hålla benchmarkresultat tillförlitliga:

  • Eliminering av död kod tar bort oanvända beräkningar.
  • Returnera ett enda resultat så att JMH konsumerar det.
  • Använd Blackhole.consume för loopar och flera värden.
  • @State-objekt håller indatan ogenomskinlig och förhindrar konstantvikning.
  • @Setup / @TearDown förbereder och rensar tillstånd på en vald Level.
Gratis att börja

Lär dig Java med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
104
Lektioner
374

Vanliga frågor

Är lektionen ”Undvik eliminering av död kod” gratis?

Ja – hela texten till ”Undvik eliminering av död kod” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Java Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i Java Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Undvik eliminering av död kod”?

Blackhole och tillstånd. Ni övar på Java Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Java Academy?

Du behöver inga förkunskaper. Utbildningen i Java Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 4 av 4.

Hur lång tid tar lektionen ”Undvik eliminering av död kod”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Java Academy-lektionen?

Ja. Varje Java Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Varför JMH
  2. Skriv ett benchmark
  3. Uppvärmning och iterationer
  4. Undvik eliminering av död kod
← Tillbaka till Java Academy