javac
将呈现字节码,该字节码是生成字节码的原始Java程序的忠实表示(除非在某些情况下它可以优化:持续折叠和死码消除)。但是,当 JVM 使用 JIT 编译器时,它可以由 JVM 执行。
对于第一个场景,看起来JVM支持内联(请参阅此处的方法,并请参阅此处以获取JVM上的内联示例)。
我找不到任何方法内联本身执行的示例。我尝试编译一些示例程序(类似于您在问题中描述的程序),即使它是,它们似乎也没有直接内联该方法。这些优化似乎是由 JVM 的 JIT 编译器完成的,而不是由 .这里方法中提到的“编译器”似乎是HotSpot JVM的JIT编译器,而不是。javac
final
javac
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
}
请注意,字节码具有 一个 代替 's 和 一个 . 是计算值。变量也是如此。如果 和 不是静态的,则生成的字节码将为:sipush 300
aload
getfield
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
}
这里也使用 an。sipush 300
对于第二种情况(死码消除),我使用了以下测试程序:
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的此页面非常有用。它描述了 HotSpot JVM 中使用的性能技术。