为什么Java编译器没有优化一个简单的方法?

Dra*_*vic 6 java bytecode javac compiler-optimization

我有一个简单的类用于说明目的:

public class Test {

    public int test1() {
        int result = 100;
        result = 200;
        return result;
    }

    public int test2() {
        return 200;
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器生成的字节码(检查者javap -c Test.class)如下:

public int test1();
Code:
   0: bipush        100
   2: istore_1
   3: sipush        200
   6: istore_1
   7: iload_1
   8: ireturn

public int test2();
Code:
   0: sipush        200
   3: ireturn
Run Code Online (Sandbox Code Playgroud)

为什么编译器没有将test1方法优化为为该方法生成的相同字节码test2?我希望它至少可以避免result变量的冗余初始化,因为很容易得出结论100根本没有使用该值.

我用Eclipse编译器和javac.

javacversion 1.8.0_72:,与Java一起作为JDK的一部分安装:

Java(TM) SE Runtime Environment (build 1.8.0_72-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.72-b15, mixed mode)
Run Code Online (Sandbox Code Playgroud)

ps9*_*s95 5

JVM优化字节码,创建了一个称为代码缓存的东西。与C ++不同,JVM可以收集有关程序的大量数据,例如,for循环有多热?那个代码块甚至值得优化吗?等等。因此,此处的优化非常有用,通常可以产生更好的结果。

如果在从java转换为字节码时(即,当您调用javac时进行了优化,则您的代码可能最适合您的计算机,但不适用于某些其他平台。因此,在此处进行优化没有任何意义。

例如,假设您的程序使用AES加密。现代CPU具有专用于AES的指令集,并带有专用硬件,以使加密速度大大提高。

如果javac尝试在编译时进行优化,则它将

  • 在软件级别上优化指令,在这种情况下,您的编程不会受益于现代CPU,或者
  • 用仅在新CPU上支持的等效CPU-AES指令替换您的AES指令,这会降低兼容​​性。

如果相反,javac将它们保留在byptcode中,则在较新的CPU上运行的JVM可以将它们识别为AES并利用此CPU功能,而在较旧的CPU上运行的JVM可以在运行时在软件级别对其进行优化(代码缓存),从而你们既最优兼容性


Raf*_*ter 4

典型的 Java 虚拟机在运行时优化程序,而不是在编译期间。在运行时,JVM 了解更多有关您的应用程序的信息,包括程序的实际行为以及执行程序的实际硬件。

字节码只是对程序应该如何运行的描述。运行时可以自由地对您的字节代码应用任何优化。

当然,有人可能会说,即使在编译期间也可以应用这种微不足道的优化,但一般来说,不将优化分布在多个步骤中是有意义的。任何优化都会有效地导致原始程序的信息丢失,这可能使其他优化变得不可能。也就是说,并非所有“最佳优化”总是显而易见的。一个简单的方法是在编译期间简单地删除(几乎)所有优化并在运行时应用它们。