Java中的静态函数内联

时间:2012-06-20 14:44:17

标签: java optimization inlining

第一个代码

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没有对此进行优化?或者它实际上是优化的,这两个代码会给出相同的,但我错过了什么?

5 个答案:

答案 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行并将其删除。