web-dev-qa-db-ja.com

メソッドのインライン化とは何ですか?

私はそれが本当に何を意味するのかを理解しようとしました:

インライン関数

C++では、クラス宣言で定義されたメンバー関数。 (2)コンパイラーが関数の実際のコードで置き換える関数呼び出し。キーワードinlineを使用して、メンバー関数または非メンバー関数の本体のインライン展開を実行するようコンパイラーに指示できます。

インライン

コンパイル中に関数呼び出しを関数のコードのコピーで置き換えるには。

たとえば、次のように記述されています。

メソッドがfinalの場合、インライン化される場合があります。

ここに: http://www.roseindia.net/javatutorials/final_methods.shtml

「インライン化される可能性がある」の意味を理解するために、例や何かを教えてもらえますか、または基本的に私を助けてくれませんか。

ありがとう。

40
Tarik

インライン化は、Java Just-In-Timeコンパイラによって実行される最適化です。

メソッドがある場合:

public int addPlusOne(int a, int b) {
  return a + b + 1;
}

あなたはこれを次のように呼びます:

public void testAddPlusOne() {
  int v1 = addPlusOne(2, 5);
  int v2 = addPlusOne(7, 13);

  // do something with v1, v2
}

コンパイラは、関数呼び出しを関数の本文で置き換えることを決定する場合があるため、結果は次のようになります。

public void testAddPlusOne() {
  int v1 = 2 + 5 + 1;
  int v2 = 7 + 13 + 1

  // do something with v1, v2
}

コンパイラーはこれを行って、各パラメーターをスタックにプッシュすることを含む、関数呼び出しを実際に行うオーバーヘッドを節約します。

これは明らかに非仮想関数に対してのみ実行できます。メソッドがサブクラスでオーバーライドされ、メソッドを含むオブジェクトのタイプが実行時までわからない場合はどうなるかを考えてみてください...コンパイラはどのコードをコピーするのかをどのように知るのでしょうか:基本クラスのメソッド本体またはサブクラスのメソッド本体? Javaではデフォルトですべてのメソッドが仮想であるため、オーバーライドできないメソッドをfinalとして明示的にマークする(またはfinalクラスに入れる)ことができます。これは、メソッドがオーバーライドされないことをコンパイラーが理解するのに役立ち、インライン化しても安全です。 (コンパイラーは、final以外のメソッドについてもこの決定を行う場合があることに注意してください。)

また、引用符内の単語mayにも注意してください。 finalメソッドは、インライン化が保証されていません。メソッドがインライン化できないことを保証できるさまざまな方法がありますが、コンパイラーをインライン化するforce方法はありません。インライン化が結果のコードの速度を損なう場合と害を及ぼす場合は、とにかくほとんど常にあなたよりよく知っています。

利点と問題の概要については wikipedia を参照してください。

67
Tom Tresansky

次のようなクラスがあるとします。

public class Demo {
    public void method() {
        // call printMessage
        printMessage();
    }

    public void printMessage() {
        System.out.println("Hello World");
    }
}

printMessageの呼び出しは、次の方法で「インライン化」できます。

public class Demo {
    public void method() {
        // call printMessage
        System.out.println("Hello World"); // <-- inlined
    }

    public void printMessage() {
        System.out.println("Hello World");
    }
}

(これは実際にはJava(バイトコードレベルでも)ではない)レベルでは行われませんが、JITコンパイル中に行われますが、上記の例はインライン化の概念を示しています。)

ここで、printMessageメソッドが別のクラスによってオーバーロードされたの場合、次のように何が起こるかを考えます。

class SubDemo extends Demo {
    public void printMessage() {
        System.out.println("Something else");
    }
}

コンパイラがDemo.printMessageへの呼び出しをインライン化した場合、オブジェクトが実際にSubDemoのインスタンスである場合、System.out.println("Hello World");でスタックしますwrong

ただし、メソッドがfinalと宣言されている場合、これはいかなる状況でも当てはまりません。メソッドが「最終」である場合は、新しい定義でオーバーライドできないため、インライン化しても安全です。

12
aioobe

関数の呼び出しは無料ではありません。呼び出された関数が完了したときにコードの呼び出しセクションに戻ることができるように、マシンはスタックフレームを維持する必要があります。スタックの維持(このスタックでの関数パラメーターの受け渡しを含む)には時間がかかります。

関数がインライン化されると、コンパイラーは関数の呼び出しを関数のコードに置き換えます。これにより、実行時の関数呼び出しによるパフォーマンスの低下を回避できます。これはプログラミングにおける古典的なトレードオフの1つです。ランタイムコードは少し大きくなります(メモリを多く消費します)が、実行は少し速くなります。

12
Chris Judge