为说明目的,我有一个简单的课程:
public class Test {
public int test1() {
int result = 100;
result = 200;
return result;
}
public int test2() {
return 200;
}
}
编译器生成的字节码(由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
为什么编译器没有将test1
方法优化为为test2
方法生成的相同字节码?我希望它至少可以避免result
变量的冗余初始化,因为很容易得出结论根本没有使用值100
。
我在Eclipse编译器和javac
中都观察到了这一点。
javac
版本:1.8.0_72
,作为JDK的一部分与Java一起安装:
Java(TM) SE Runtime Environment (build 1.8.0_72-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.72-b15, mixed mode)
答案 0 :(得分:4)
JVM优化字节码,创建称为 代码缓存 的东西。与C ++不同,JVM可以收集大量有关程序的数据,例如循环有多热?,该代码块是否值得优化?等等。这里的优化非常有用,并且通常会产生更好的结果。
如果在从java转换为字节码时进行优化(即,当您调用 javac 时),您的代码可能是您的计算机的最佳选择,但不适用于某些不同的平台 。所以在这里进行优化是没有意义的。
作为示例,假设您的程序使用AES加密。现代CPU具有AES特定的指令集,使用特殊硬件使加密速度更快。
如果 javac 尝试在编译时进行优化,那么它将
如果 javac 将它们保留在byptcode中,那么在较新的CPU上运行的JVM可以将它们识别为AES并利用此CPU功能,而在较旧的CPU上运行的JVM可以在运行时的软件级别(代码缓存),为您提供最优性和兼容性。
答案 1 :(得分:4)
典型的Java虚拟机在运行时优化您的程序,而不是在编译期间。在运行时,JVM对应用程序有更多了解,包括程序的实际行为以及程序执行的实际硬件。
字节代码仅仅是对程序应该如何表现的描述。运行时可以自由地对字节代码应用任何优化。
当然,人们可以争辩说,即使在编译过程中也可以应用这种简单的优化,但总的来说,不通过几个步骤分配优化是有意义的。任何优化都会有效地导致关于原始程序的信息丢失,这可能使其他优化变得不可能。这说,并非所有"最好的优化"总是显而易见的。一个简单的方法是在编译期间简单地删除(几乎)所有优化,并在运行时应用它们。