javac
представит байт-код, который является точным представлением исходной Java-программы, сгенерировавшей байт-код (за исключением определенных ситуаций, когда он может оптимизировать: постоянное свертывание и устранение мертвого кода ).Однако оптимизация может выполняться JVM, когда она использует JIT-компилятор.
Для первого сценария выглядит, что JVM поддерживает встраивание (см. Методы здесь и посмотрите здесь для примера встраивания в JVM.
Я не смог найти никаких примеров встраивания метода, выполняемого самой javac
.Я попытался скомпилировать несколько примеров программ (похожих на ту, что вы описали в своем вопросе), и ни одна из них, похоже, не содержала прямого метода, даже когда он был final
.Казалось бы, такого рода оптимизации выполняются JIT-компилятором JVM, а не javac
.«Компилятор», упомянутый в Methods здесь , кажется JIT-компилятором HotSpot JVM, а не javac
.
Из того, что я вижу, javac
поддерживает устранение мертвого кода (см. Пример для второго случая) и постоянное свертывание .При свертывании констант компилятор будет предварительно вычислять выражения констант и использовать вычисленное значение вместо выполнения вычислений во время выполнения.Например:
public class ConstantFolding {
private static final int a = 100;
private static final int b = 200;
public final void baz() {
int c = a + b;
}
}
компилируется в следующий байт-код:
Compiled from "ConstantFolding.java"
public class ConstantFolding extends java.lang.Object{
private static final int a;
private static final int b;
public ConstantFolding();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public final void baz();
Code:
0: sipush 300
3: istore_1
4: return
}
Обратите внимание, что байт-код имеет sipush 300
вместо aload
'* getfield
s и iadd
.300
- расчетное значение.Это также относится и к private final
переменным.Если a
и b
не были статическими, результирующий байт-код будет иметь вид:
Compiled from "ConstantFolding.java"
public class ConstantFolding extends java.lang.Object{
private final int a;
private final int b;
public ConstantFolding();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 100
7: putfield #2; //Field a:I
10: aload_0
11: sipush 200
14: putfield #3; //Field b:I
17: return
public final void baz();
Code:
0: sipush 300
3: istore_1
4: return
}
Здесь также используется sipush 300
.
Для второго случая (dead-Исключение кода), я использовал следующую тестовую программу:
public class InlineTest {
private static final boolean debug = false;
private void baz() {
if(debug) {
String a = foo();
}
}
private String foo() {
return bar();
}
private String bar() {
return "abc";
}
}
, которая дает следующий байт-код:
Compiled from "InlineTest.java"
public class InlineTest extends java.lang.Object{
private static final boolean debug;
public InlineTest();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
private void baz();
Code:
0: return
private java.lang.String foo();
Code:
0: aload_0
1: invokespecial #2; //Method bar:()Ljava/lang/String;
4: areturn
private java.lang.String bar();
Code:
0: ldc #3; //String abc
2: areturn
}
Как видите, foo
вообще не вызывается вbaz
потому что код внутри блока if
фактически "мертв".
В Sun (сейчас Oracle) HotSpot JVM объединяет интерпретацию байт-кода и компиляцию JIT.Когда байт-код представляется в JVM, код первоначально интерпретируется, но JVM будет контролировать байт-код и выбирать части, которые часто выполняются.Он включает эти части в собственный код, чтобы они работали быстрееДля части байт-кода, которая не используется так часто, эта компиляция не выполнена.Это также хорошо, потому что компиляция имеет некоторые издержкиТак что это действительно вопрос компромисса.Если вы решите скомпилировать весь байт-код в собственный код, тогда у кода может быть очень большая задержка запуска.
В дополнение к мониторингу байт-кода JVM также может выполнять статический анализ байт-кода во время его интерпретации.и загрузите его для дальнейшей оптимизации.
Если вы хотите знать конкретные виды оптимизации, которые выполняет JVM, эта страница в Oracle очень полезна.Он описывает методы производительности, используемые в JSM HotSpot.