Предотвращение удаления неиспользуемого кода
Blackhole и состояние
«Предотвращение удаления неиспользуемого кода» — бесплатный урок Java Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Как избежать устранения мёртвого кода
Главная ловушка микротестирования — устранение мёртвого кода (DCE): если JIT доказывает, что результат нигде не используется, он удаляет вычисление. Тогда Ваш микротест не измеряет ничего. JMH предоставляет два инструмента для предотвращения этого: возврат значений и Blackhole.
Ловушка устранения мёртвого кода
Этот цикл миллион раз вычисляет квадратный корень, но никогда не использует результат. Умный компилятор может удалить весь цикл.
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 и вызовите consume(...). Поглотитель убеждает 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 (один раз), 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.
Возврат нескольких значений
Если тест производительности естественным образом выдаёт два результата, можно вернуть один, а другой передать через 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 использовать в циклах и случаях с несколькими значениями.
Проверяйте правдоподобие чисел
Если тест производительности показывает неправдоподобно малое время (менее наносекунды для настоящей работы), подозревайте DCE или свёртку констант. Проверьте ещё раз, что результаты возвращаются или потребляются, а входные данные поступают из @State.
Собираем всё вместе
Надёжный тест производительности должен читать входные данные из объекта @State, выполнять работу, а затем либо return результат, либо передавать его в Blackhole.consume. Благодаря этим трём привычкам DCE и свёртка констант не смогут исказить результаты измерений.
Быстрая проверка
Проверьте, насколько хорошо Вы умеете предотвращать устранение мёртвого кода.
Итоги
Вы научились делать результаты тестов производительности достоверными:
- Устранение мёртвого кода удаляет неиспользуемые вычисления.
- Возвращайте один результат, чтобы JMH его потреблял.
- Используйте Blackhole.consume для циклов и нескольких значений.
- Объекты @State скрывают входные данные, предотвращая свёртку констант.
- @Setup / @TearDown подготавливают и очищают состояние на выбранном уровне.
Часто задаваемые вопросы
Урок «Предотвращение удаления неиспользуемого кода» бесплатный?
Да — полный текст урока «Предотвращение удаления неиспользуемого кода» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «Предотвращение удаления неиспользуемого кода»?
Blackhole и состояние Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Предотвращение удаления неиспользуемого кода»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Зачем нужен JMH
- Написание измерения производительности
- Прогрев и итерации
- Предотвращение удаления неиспользуемого кода