第一个代码:
public static int pitagoras(int a, int b)
{
return (int) Math.sqrt(a*a + b*b);
}
public static int distance(int x, int y, int x2, int y2)
{
return pitagoras(x - x2, y - y2);
}
经常会调用 distance
。当我用javac
编译它然后用javap -c
反编译时,我得到了这个字节码:
public static int pitagoras(int, int);
Code:
0: iload_0
1: iload_0
2: imul
3: iload_1
4: iload_1
5: imul
6: iadd
7: i2d
8: invokestatic #24; //Method java/lang/Math.sqrt:(D)D
11: d2i
12: ireturn
public static int distance(int, int, int, int);
Code:
0: iload_0
1: iload_2
2: isub
3: iload_1
4: iload_3
5: isub
6: invokestatic #34; //Method pitagoras:(II)I
9: ireturn
似乎javac
没有优化第二个函数distance
。
第二段代码,我认为,更快:
public static int distance(int x, int y, int x2, int y2)
{
return (int) Math.sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2));
}
及其字节码:
public static int distance(int, int, int, int);
Code:
0: iload_0
1: iload_2
2: isub
3: iload_0
4: iload_2
5: isub
6: imul
7: iload_1
8: iload_3
9: isub
10: iload_1
11: iload_3
12: isub
13: imul
14: iadd
15: i2d
16: invokestatic #24; //Method java/lang/Math.sqrt:(D)D
19: d2i
20: ireturn
invokestatic
是否如此之快以至于它与内联静态函数相同?为什么javac
没有对此进行优化?或者它实际上是优化的,这两个代码会给出相同的,但我错过了什么?
答案 0 :(得分:7)
javac
没有优化。这是JVM实现的工作(通常是HotSpot)。
在javac
中曾经有过一些优化但是它们使代码变得复杂,并且据称倾向于安排代码以便HotSpot优化被禁止。
HotSpot优化通常在数千次迭代后动态完成(可配置,默认取决于使用“客户端”,“服务器”还是分层版本)。
语言规范要求javac
做一些事情,例如内联常量和组合文字字符串。
答案 1 :(得分:4)
Java语言没有定义内联函数。许多(也许是大多数)即时(JIT)编译器将动态地(在运行时)用内联代码替换这样的静态函数调用。
答案 2 :(得分:1)
我相信两个版本的性能都相似,因为JVM使用JIT来提高性能。
答案 3 :(得分:1)
您正在寻找的那种优化(内联)不一定会在编译时发生,但很有可能Just in Time(JIT)编译器将在运行时执行它。
因此,您不太可能在字节代码级别看到内联发生,更可能的是,它将在程序执行期间在本机代码级别发生。
答案 4 :(得分:1)
给出的答案是正确的:javac没有内联方法,因为它可能不是最好的方法。
假设distance()
方法偶尔被调用一次但不常见。通过内联pitagoras()
和内容来优化它会减慢编译速度,因为它几乎不会被使用。
另一方面,Hotspot知道何时调用方法以及调用方法的次数。如果经常执行该方法,那么Hotspot可以内联它并将其编译为本机代码,但前提是它可以提高性能。请记住,如果优化是好事,Hotspot是唯一知道的组件。
另外,请注意javac可以进行一次优化:它可以消除死代码。考虑这个课程:
public class Test {
public final static boolean ENABLED=false;
public static void main(String... args) {
if(ENABLED)
System.out.println("Hello World");
}
}
main方法的编译字节码是:
public static void main(java.lang.String[]);
Code:
0: return
=> javac检测到无法访问println
行并将其删除。