Що таке постійне складання (Constant Folding)?
Постійне складання (Constant Folding) — це техніка оптимізації компілятора, при якій JVM обчислює постійні вирази на етапі компіляції, замість того, щоб виконувати ці обчислення під час виконання програми.
Що таке постійне складання (Constant Folding)?
Постійне складання (Constant Folding) — це техніка оптимізації компілятора, при якій JVM оцінює вирази з постійними значеннями на етапі компіляції, замість того, щоб обчислювати їх під час виконання програми.
Простий приклад
Базова арифметика
// До постійного складання
int value = 60 * 24 * 365;
// Після постійного складання (що насправді потрапляє в байт-код)
int value = 525600; // Обчислено на етапі компіляції
Конкатенація рядків
// До постійного складання
String message = "Hello" + " " + "World";
// Після постійного складання
String message = "Hello World"; // Один постійний рядок в байт-коді
Коли це відбувається?
Константи часу компіляції
public class ConstantExample {
// Обчислено на етапі компіляції
private static final int MINUTES_IN_YEAR = 60 * 24 * 365;
// Не обчислюється на етапі компіляції (потрібна інформація під час виконання)
private static final int DYNAMIC_VALUE = Math.random() > 0.5 ? 1 : 2;
}
public class ConstantFolding {
// Результат цього методу буде постійно складений
static final int computeMaxAge() {
return 60 * 24 * 365; // Буде складено в 525600
}
}
Поле final
public class FinalExample {
// Може бути постійно складено
private final int CONSTANT = 100 * 100;
// Не може бути постійно складено (значення відоме лише під час конструювання)
private final int constructorValue;
public FinalExample(int value) {
this.constructorValue = value * 100;
}
}
Складні приклади
Математичні вирази
public class MathExample {
// Буде складено
private static final double CIRCLE_RADIANS = 2 * Math.PI;
// НЕ буде складено (Math.sin не є сталим виразом)
private static final double SINE_VALUE = Math.sin(Math.PI / 2);
}
Операції з рядками
public class StringExample {
// Буде складено
private static final String GREETING = "Hello".toUpperCase() + "!";
// НЕ буде складено (залежить від локалі під час виконання)
private static final String LOCALE_GREETING =
"Hello".toLowerCase(Locale.getDefault());
}
Перевірка постійного складання
Ми можемо використати javap
, щоб побачити байт-код і перевірити постійне складання:
javac YourClass.java
javap -c YourClass
Перед тим, як зануритись у вивчення байт-коду, давайте поглянемо на список інструкцій, які використовуються для завантаження констант: Розуміння інструкцій завантаження констант JVM.
Приклад без постійного складання
public class NoFolding {
public int calculate(int x) {
return x * 60 * 24; // Не складено, бо x — змінна
}
}
немає постійного складання (для малих цілих чисел використовується bipush)
Приклад з постійним складанням
public class WithFolding {
public int getMinutesInDay() {
return 60 * 24; // Складено в 1440 в байт-коді
}
}
постійне складання в дії
sipush
— додає коротке ціле число на стек операндів1440
— постійне значення, яке додається (в даному випадку,60 * 24
, яке було складено!)
Приклад: static vs static final
class Final {
private static final int A_NUMBER = 2 * 2 * 2;
private static int secondsInDay = 24 * 60 * 60;
public void printValues() {
System.out.println(A_NUMBER); // Безпосередньо використовує 86400
System.out.println(secondsInDay); // Завантажує з поля
}
}
A_NUMBER
є константою, вона навіть не з'являється в байт-коді! Це тому, що це static final
, яке обчислюється на етапі компіляції, тому його значення (86400
) безпосередньо вбудоване у байт-код, де б не використовувалася ця константа.
Для secondsInDay
ми бачимо:
- Обчислення (
24 * 60 * 60
) було складено в86400
- Значення потрібно завантажити (
ldc
) і зберегти (putstatic
) у поле, оскільки воно не є final - Воно з’являється в статичному ініціалізаторі (
static {}
), оскільки є статичним полем
Переваги
Покращена продуктивність
- Не потрібно обчислення під час виконання
- Зменшена кількість інструкцій
- Краща використання кешу процесора (незначний вплив)
Зменшений розмір коду
- Багато операцій замінено на одну константу
- Менший байт-код
Перекладено з: Constant Folding in the JVM