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

javac2番目の関数が最適化されていないようですdistance

2番目のコードは、私が思うに、より速く:

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これを最適化しなかったのですか?あるいは、実際には最適化されており、これら2つのコードで同じ結果が得られるかもしれませんが、何かが足りませんか?

4

5 に答える 5

7

javac最適化しません。これがJVM実装(通常はHotSpot)の仕事です。

以前はいくつかの最適化がありましjavacたが、それらはコードを複雑にし、HotSpotの最適化が禁止されるようにコードを配置する傾向があったとされています。

HotSpotの最適化は、通常、数千回の反復後に動的に実行されます(構成可能、デフォルトは「クライアント」、「サーバー」、または階層型バージョンのいずれを使用するかによって異なります)。

javac定数のインライン化やリテラル文字列の結合など、言語仕様で実行する必要のあることがいくつかあります。

于 2012-06-20T14:47:48.713 に答える
4

Java言語では、インライン関数は定義されていません。多くの(おそらくほとんどの)Just-In-Time(JIT)コンパイラーは、動的に(実行時に)そのような静的関数呼び出しをインライン化されたコードに置き換えます。

于 2012-06-20T14:48:33.087 に答える
1

JVMはJITを使用してパフォーマンスを向上させるため、両方のバージョンのパフォーマンスは同じになると思います。

于 2012-06-20T14:49:12.567 に答える
1

探している(インライン化)最適化の種類は、必ずしもコンパイル時に発生するわけではありませんが、Just in Time(JIT)コンパイラが実行時に実行する可能性は十分にあります。

したがって、インライン化がバイトコードレベルで発生することを確認できる可能性は低く、プログラムの実行中にネイティブコードレベルで発生する可能性が高くなります。

于 2012-06-20T14:49:32.633 に答える
1

与えられた答えは正しいです:javacは、最善の方法ではない可能性があるため、メソッドをインライン化しません。

メソッドがたまにdistance()呼び出されますが、それほど頻繁ではないとします。インライン化などによって最適化すると、pitagoras()ほとんど使用されていないもののコンパイルが遅くなります。

一方、Hotspotは、メソッドがいつ呼び出され、何回呼び出されたかを認識しています。メソッドが頻繁に実行される場合、ホットスポットはそれをインライン化してネイティブコードにコンパイルすることがありますが、それはパフォーマンスが向上する場合に限られます。ホットスポットは、最適化が良いことかどうかを知る唯一のコンポーネントであることを忘れないでください。

また、javacは1つの最適化を行う可能性があることに注意してください。デッドコードを排除します。このクラスを考えてみましょう:

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 に答える