在“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文件,并包含了所有行。我如何检查它是否如上所述工作?
答案 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循环。