Константне складання в JVM

Що таке постійне складання (Constant Folding)?

Постійне складання (Constant Folding) — це техніка оптимізації компілятора, при якій JVM обчислює постійні вирази на етапі компіляції, замість того, щоб виконувати ці обчислення під час виконання програми.

Що таке постійне складання (Constant Folding)?

Постійне складання (Constant Folding) — це техніка оптимізації компілятора, при якій JVM оцінює вирази з постійними значеннями на етапі компіляції, замість того, щоб обчислювати їх під час виконання програми.

pic

Простий приклад

Базова арифметика

// До постійного складання  
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 — змінна  
 }  
}

pic

немає постійного складання (для малих цілих чисел використовується bipush)

Приклад з постійним складанням

public class WithFolding {  
 public int getMinutesInDay() {  
 return 60 * 24; // Складено в 1440 в байт-коді  
 }  
}

pic

постійне складання в дії

  • 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) безпосередньо вбудоване у байт-код, де б не використовувалася ця константа.

pic

Для secondsInDay ми бачимо:

  • Обчислення (24 * 60 * 60) було складено в 86400
  • Значення потрібно завантажити (ldc) і зберегти (putstatic) у поле, оскільки воно не є final
  • Воно з’являється в статичному ініціалізаторі (static {}), оскільки є статичним полем

Переваги

Покращена продуктивність

  • Не потрібно обчислення під час виконання
  • Зменшена кількість інструкцій
  • Краща використання кешу процесора (незначний вплив)

Зменшений розмір коду

  • Багато операцій замінено на одну константу
  • Менший байт-код

Перекладено з: Constant Folding in the JVM

Leave a Reply

Your email address will not be published. Required fields are marked *