2011-01-04 7 views
4

私はいくつかのコードを素早くマークしていました(いいですね)、このパズルを見つけました。リフレクションを使用してフィールドを読むとき、getterメソッドを呼び出す方がFieldを読み込むよりも速いです。Javaリフレクションメソッドの呼び出しでは、結果がFieldsより速くなりますか?

簡単なテストクラス:

Method m = Foo.class.getDeclaredMethod("getVal", null); 
Field f = Foo.class.getDeclaredField("val"); 

は、今私は、ループ内で2回反射を呼び出すフィールド上手法に関する invoke、および get

private static final class Foo { 
    public Foo(double val) { 
     this.val = val; 
    } 
    public double getVal() { return val; } 
    public final double val; // only public for demo purposes 
} 

我々は2回の反射を持っています。最初の実行はVMをウォームアップするために実行され、2回目の実行は10Mの繰り返しで実行されます。 メソッド呼び出しは一貫して30%高速ですが、なぜですか? getDeclaredMethodとgetDeclaredFieldはであり、ループ内では呼び出されていません。です。それらは一度呼び出され、ループ内の同じオブジェクトに対して実行されます。

私はまた、いくつかのマイナーなバリエーションを試しました。フィールドを非最終、推移、非公開などにしました。これらの組み合わせのすべてが統計的に同じパフォーマンスをもたらしました。

編集:これはWinXP、Intel Core2 Duo、Sun JavaSEビルド1.6.0_16-b01、jUnit4とEclipseで動作します。

+0

質問がありますか? –

+0

これは太字の文章です。 – omerkudat

答えて

3

getDeclaredFieldとgetDeclaredMethodがどのように実装されているかの違いがわかります。getDeclaredFieldは、呼び出されるたびに、実際のオブジェクトまたはプリミティブ型getDeclaredMethodを返すために変数の型とサイズをチェックする必要があります残りのすべてを静的に処理する同じメソッドへのポインタを返します。

編集

私の説明は同様である:各オブジェクトのインスタンスが異なるプロパティ値を有することができる方法は、クラスごとに一度だけメモリに含まれています。メソッド呼び出しを実行してプロパティ値を取得すると(メソッドポインタのみを使用している)、コンパイラはパラメータにアクセスするメソッドを最適化し、正確なクラス階層などを知っています。また、get "、あなたはリフレクションにゲッターメソッドの仕事をさせ、明らかにコンパイラの最適化はできません。

+0

私は質問に明確化を加えました。これらのメソッドは、ループの外で一度呼び出されます。ループにはリフレクションの呼び出しのみが含まれます。 – omerkudat

+0

これをクリアしていただきありがとうございます。私はそれに応じて私の答えを編集しました。 – weltraumpirat

+0

各インスタンスのオブジェクトのメモリレイアウトは同じではないでしょうか?私は、フィールドがオブジェクトアドレスから特定のオフセットを読み込む最適化をもたらすことができると思います。クラスはfinalクラスであるため、サブクラスのレイアウトは干渉しません。 – omerkudat

0

これはまた、double d = Foo.getVal()double d = Foo.valより30%速いことを意味しますか?

+1

いいえ、確かにそうではありません。反射は単純な割り当てよりもずっと遅いです。 –

+0

私は人々がゲッターを露出したフィールドに置き換えることを急いでいると想像することができるので、これが当てはまらないことを願っています。 – omerkudat

1

マイクロベンチマークでは、ループ内でJVM/Hotspotによる最適化が行われるため、メソッド呼び出しが高速になります。ここでループしてください

はあなたmicrobenchmakを変更

反射によって値を読み取ると、その後、(例えば)1を増加させ、その後、リフレクション経由で同じフィールドに割り当てます。ループの外側では、最終的な読み込みとSystem.out.printlnを行います。

2つのバリアント(フィールドとメソッド)を実行すると、実際の違いはちょうど反対です。メソッドの呼び出しは実際には30です-40%遅くなります。

よろしくお願いいたします。

関連する問題