如何确定编译器如何优化代码?

时间:2016-02-06 19:12:57

标签: java performance

在“Java Performance The Definite Guide”中,有一个示例显示了编写微基准测试的问题。 代码是这样的:

Completed

这本书提到“智能编译器将最终执行此代码”:

public void test(){
    double l;
    long then = System.currentTimeMillis();
    for (int i = 0; i < n; i++) {
        l = fib(50);
    }
    long now = System.currentTimeMillis();
    System.out.println("Time: " + (now - then));
}

我看到“l”是一个本地未使用的变量,忽略它是有意义的,但我不知道它是如何完成的,或者如何证明它是这样的。我尝试运行代码,似乎执行了fib()方法。 我还查看了.class文件,并包含了所有行。我如何检查它是否如上所述工作?

2 个答案:

答案 0 :(得分:3)

您正在将Java源代码与字节码编译器(如javac)和HotSpot的即时编译器混合在一起。 javac未执行优化,因此您不会在.class文件中看到优化。

这是HotSpot引擎,或者通常是JVM,它将根据代码分析和程序的运行时行为执行优化。您无法看到这些效果(除了性能差异),因为您可以采取任何措施来检测差异,例如放置打印语句(或任何带副作用的东西)或在方法中设置断点,将禁用优化,当然,优化不能改变正在运行的程序的语义。

然而,检测方法的结果可能仍然是伪装。当您在方法中放置System.out.println("hello");之类的语句时,将相应地打印字符串"hello",但是看到hello消息并不能证明数字计算确实发生了,如果结果尚未使用。

答案 1 :(得分:0)

要检查编译器的功能,可以使用javap -c反汇编类。反汇编编译版本的输出的相关部分:

   0: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J
   3: lstore        4
   5: iconst_0
   6: istore        6
   8: iload         6
  10: iload_1
  11: if_icmpge     27
  14: aload_0
  15: bipush        50
  17: invokevirtual #3                  // Method fib:(I)D
  20: dstore_2
  21: iinc          6, 1
  24: goto          8
  27: invokestatic  #2                  // Method java/lang/System.currentTimeMillis:()J

for循环从8开始,循环计数器增加到21,循环为24。

但是,我尝试将其转换为C并使用gcc -c -O3进行编译,然后删除整个for循环。