Java Academy · Lektion

Undgå dead-code elimination

Blackhole og state

Lektion 4 af 413 trin

Undgå dead-code elimination er en gratis Java Academy-lektion på CoddyKit. Dette er lektion 4 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Java Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Java Academy-kurset indeholder 4 lektioner i alt.

Undgå eliminering af død kode

Den største faldgrube ved mikrobenchmarking er eliminering af død kode (DCE): Hvis JIT kan bevise, at et resultat aldrig bruges, sletter den beregningen. Dit benchmark måler så ingenting. JMH giver dig to værktøjer til at forhindre dette — returværdier og Blackhole.

DCE-fælden

Denne løkke beregner en kvadratrod en million gange, men bruger aldrig resultatet. En intelligent compiler kan slette hele løkken.

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: Returnér resultatet

Det enkleste forsvar er at returnere den beregnede værdi fra @Benchmark-metoden. JMH bruger alle returnerede værdier, så JVM kan ikke bevise, at de er døde.

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 et benchmark producerer flere værdier, eller du ikke kan returnere én, skal du indsætte en Blackhole og kalde consume(...). Blackhole overbeviser JIT om, at hver værdi bruges, uden omkostningen ved faktisk arbejde.

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

En @State-klasse indeholder input, der er uigennemsigtige for optimeringsværktøjet, og dermed forhindrer konstantfoldning. JMH opretter en instans af den og sender den til dit benchmark. Omfanget kan være Thread, Benchmark (delt) 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 og @TearDown

I en @State-klasse kører metoder, der er annoteret med @Setup, før målingen, og @TearDown efter den. Level styrer hyppigheden: Trial (én gang), 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;
    }
}

Undgå konstante input

Tilfør aldrig bogstavelige konstanter til den metode, der testes. Math.sqrt(2.0) kan foldes til en konstant, mens Math.sqrt(state.value) ikke kan. Hent altid input fra et @State-felt.

Returnering af flere værdier

Hvis dit benchmark naturligt producerer to resultater, kan du returnere det ene og forbruge det andet via en Blackhole eller kombinere dem. Hvis et af dem ikke forbruges, åbner du igen for DCE-hullet.

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

Omkostninger ved Blackhole

Blackhole er designet til at være ekstremt billig og selv modstandsdygtig over for optimering, men den er ikke helt gratis. Ved ultrahurtige operationer bør du foretrække at returnere en enkelt værdi og bruge Blackhole til løkker og tilfælde med flere værdier.

Kontrollér dine tal

Hvis et benchmark rapporterer en umuligt lav tid (under et nanosekund for reelt arbejde), så mistænk DCE eller konstantfoldning. Kontrollér igen, at resultater returneres eller forbruges, og at input kommer fra @State.

Sæt det hele sammen

Et robust benchmark læser input fra et @State-objekt, udfører arbejdet og enten returnerer resultatet eller forbruger det med Blackhole.consume. Med disse tre vaner kan DCE og konstantfoldning ikke forvrænge dine målinger.

Hurtig kontrol

Kontrollér din forståelse af, hvordan eliminering af død kode forhindres.

Opsummering

Du har lært at holde benchmarks ærlige:

  • Eliminering af død kode sletter ubrugte beregninger.
  • Returnér et enkelt resultat, så JMH kan forbruge det.
  • Brug Blackhole.consume til løkker og flere værdier.
  • @State-objekter holder input skjult og forhindrer konstantfoldning.
  • @Setup / @TearDown forbereder og rydder op i tilstanden på et valgt Level.
Gratis at komme i gang

Lær Java med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
104
Lektioner
374

Ofte stillede spørgsmål

Er lektionen “Undgå dead-code elimination” gratis?

Ja — hele teksten til “Undgå dead-code elimination” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Java Academy-kurset, skal du opgradere til CoddyKit PRO. Java Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Undgå dead-code elimination”?

Blackhole og state Du øver dig i Java Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Java Academy?

Der kræves ingen tidligere erfaring. Java Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 4 af 4.

Hvor lang tid tager lektionen “Undgå dead-code elimination”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Java Academy-lektion?

Ja. Alle Java Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Hvorfor JMH
  2. Skriv et benchmark
  3. Warmup og iterationer
  4. Undgå dead-code elimination
← Tilbage til Java Academy