Cómo evitar la eliminación de código muerto
Blackhole y estado
Cómo evitar la eliminación de código muerto es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Java Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Java Academy incluye 4 lecciones en total.
Evitar la eliminación de código muerto
La mayor trampa de los microbenchmarks es la eliminación de código muerto (DCE): si el JIT demuestra que un resultado nunca se utiliza, elimina el cálculo. En ese caso, su benchmark no mide nada. JMH ofrece dos herramientas para evitarlo: devolver valores y usar Blackhole.
La trampa del DCE
Este bucle calcula una raíz cuadrada un millón de veces, pero nunca utiliza el resultado. Un compilador inteligente puede eliminar el bucle completo.
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));
}
}Solución 1: devolver el resultado
La defensa más sencilla consiste en devolver el valor calculado desde el método @Benchmark. JMH consume todos los valores devueltos, por lo que la JVM no puede demostrar que no se utilizan.
import org.openjdk.jmh.annotations.Benchmark;
public class Bench {
@Benchmark
public double sqrt() {
return Math.sqrt(42.0); // returned -> consumed by JMH
}
}Solución 2: Blackhole
Cuando un benchmark produce varios valores o no puede devolver uno, inyecte un Blackhole y llame a consume(...). Blackhole convence al JIT de que cada valor se utiliza, sin el coste de realizar trabajo real.
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));
}
}
}Objetos @State
Una clase @State contiene entradas que son opacas para el optimizador, lo que impide el plegado de constantes. JMH crea una instancia y se la pasa a su benchmark. El ámbito puede ser Thread, Benchmark (compartido) o 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 y @TearDown
Dentro de una clase @State, los métodos anotados con @Setup se ejecutan antes de la medición y los anotados con @TearDown, después. Level controla la frecuencia: Trial (una vez), Iteration o 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;
}
}Evite las entradas constantes
No proporcione nunca constantes literales al método bajo prueba. Math.sqrt(2.0) puede plegarse en una constante; Math.sqrt(state.value) no. Obtenga siempre las entradas de un campo @State.
Devolver varios valores
Si su benchmark genera naturalmente dos resultados, puede devolver uno y consumir el otro mediante Blackhole, o combinarlos. Dejar cualquiera de los dos sin consumir vuelve a abrir el problema de 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;
}
}Sobrecoste de Blackhole
Blackhole está diseñado para ser extremadamente barato y resistente a la optimización, pero no es completamente gratuito. Para operaciones ultrarrápidas, prefiera devolver un único valor; reserve Blackhole para bucles y casos con varios valores.
Compruebe la coherencia de sus mediciones
Si un benchmark informa de un tiempo imposiblemente bajo (inferior a un nanosegundo para trabajo real), sospeche de DCE o del plegado de constantes. Compruebe de nuevo que los resultados se devuelvan o se consuman y que las entradas procedan de @State.
Cómo ponerlo todo en práctica
Un benchmark sólido: lea las entradas de un objeto @State, realice el trabajo y devuelva el resultado o consúmalo mediante Blackhole.consume. Con estos tres hábitos, DCE y el plegado de constantes no pueden falsear sus mediciones.
Comprobación rápida
Compruebe su comprensión de cómo evitar la eliminación de código muerto.
Resumen
Ha aprendido a mantener la honestidad de los benchmarks:
- La eliminación de código muerto borra los cálculos que no se utilizan.
- Return devuelve un único resultado para que JMH lo consuma.
- Use Blackhole.consume para bucles y varios valores.
- Los objetos @State mantienen las entradas opacas y evitan el plegado de constantes.
- @Setup / @TearDown preparan y limpian el estado en un nivel elegido.
Preguntas frecuentes
¿La lección «Cómo evitar la eliminación de código muerto» es gratis?
Sí — el texto completo de «Cómo evitar la eliminación de código muerto» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Java Academy, actualiza a CoddyKit PRO. El curso de Java Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Cómo evitar la eliminación de código muerto»?
Blackhole y estado Practicas Java Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Java Academy?
No se requiere experiencia previa. Java Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «Cómo evitar la eliminación de código muerto»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Java Academy?
Sí. Cada lección de Java Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Por qué usar JMH
- Escritura de un benchmark
- Calentamiento e iteraciones
- Cómo evitar la eliminación de código muerto