5

第一个代码

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

4

5 回答 5

7

javac不优化。这就是 JVM 实现(通常是 HotSpot)的工作。

过去有一些优化,javac但它们使代码复杂化,据称倾向于安排代码以抑制 HotSpot 优化。

HotSpot 优化通常在数千次迭代后动态完成(可配置,默认取决于使用“客户端”、“服务器”还是分层版本)。

语言规范需要做一些事情javac,例如内联常量和组合文字字符串。

于 2012-06-20T14:47:48.713 回答
4

Java 语言没有定义内联函数。许多(也许是大多数)即时 (JIT) 编译器将动态地(在运行时)将此类静态函数调用替换为内联代码。

于 2012-06-20T14:48:33.087 回答
1

我相信两个版本的性能会相似,因为 JVM 使用 JIT 来提高性能。

于 2012-06-20T14:49:12.567 回答
1

您正在寻找的优化类型(内联)不一定发生在编译时,但准时 (JIT) 编译器很可能会在运行时执行它。

因此,您不太可能看到内联发生在字节码级别,更有可能的是,它会在程序执行期间发生在本机代码级别。

于 2012-06-20T14:49:32.633 回答
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无法到达该行并将其删除。

于 2012-06-20T15:42:53.283 回答