2013-02-12 11 views
6

ゲッター/セッターと直接フィールドアクセスを使用するときの速度の違いを調べるためにいくつかのテストを行っていました。私はこのような単純なベンチマークアプリケーションを書いた:メソッドアクセスがフィールドアクセスより速いように見えるのはなぜですか?

public class FieldTest { 

    private int value = 0; 

    public void setValue(int value) { 
     this.value = value; 
    } 

    public int getValue() { 
     return this.value; 
    } 

    public static void doTest(int num) { 
     FieldTest f = new FieldTest(); 

     // test direct field access 
     long start1 = System.nanoTime(); 

     for (int i = 0; i < num; i++) { 
      f.value = f.value + 1; 
     } 
     f.value = 0; 

     long diff1 = System.nanoTime() - start1; 

     // test method field access 
     long start2 = System.nanoTime(); 

     for (int i = 0; i < num; i++) { 
      f.setValue(f.getValue() + 1); 
     } 
     f.setValue(0); 

     long diff2 = System.nanoTime() - start2; 

     // print results 
     System.out.printf("Field Access: %d ns\n", diff1); 
     System.out.printf("Method Access: %d ns\n", diff2); 
     System.out.println(); 
    } 

    public static void main(String[] args) throws InterruptedException { 
     int num = 2147483647; 

     // wait for the VM to warm up 
     Thread.sleep(1000); 

     for (int i = 0; i < 10; i++) { 
      doTest(num); 
     } 
    } 

} 

私はそれを実行するたびに、私はこのような一貫性のある結果を得る:http://pastebin.com/hcAtjVCL

フィールドアクセスが遅くなるように思われる理由を誰かが私に説明することができれば、私は思っていましたgetter/setterメソッドへのアクセスよりも、最後の8回の反復が信じられないほど高速に実行される理由もあります。


編集http://pastebin.com/wxiDdRix:アカウントへassyliasStephen Cコメントを取られたので、私は私がわずかに異なる結果を得たhttp://pastebin.com/Vzb8hGdcにコードを変更しました。

+2

私はコンパイラがゲッターをとにかくインライン化すると思います。バイトコードをチェックしましたか? – jlordo

+10

'/ * VMがウォーミングアップするのを待つ*/Thread.sleep(1000);' - それは動作しません。 JVMは何もしなければウォーミングアップしません...あなたのマイクロベンチマークにはいくつかの欠陥があります。特に、(i)JVMのウォームアップを許可していない(ii)テストする2つのパスが同じメソッドにあるため、いくつかの最適化を妨げる可能性があります。 – assylias

+11

@jlordo - インライン展開はJITコンパイラによって行われます。私はバイトコードで明白ではないでしょう。 –

答えて

9

あなたのベンチマークが壊れているという説明です。

最初の反復はインタープリタを使用して行われます。

Field Access: 1528500478 ns 
Method Access: 1521365905 ns 

2番目の反復はインタプリタによって開始され、実行中のJITコンパイル済みコードに戻ります。

Field Access: 1550385619 ns 
Method Access: 47761359 ns 

残りの繰り返しはすべてJITコンパイル済みコードを使用して行われます。彼らは信じられないほど速いです

Field Access: 68 ns 
Method Access: 33 ns 

etcetera 

理由は、JITコンパイラがが離れてをループを最適化していることです。彼らは計算に役立つものは何も寄与していないことを発見しました。 (最初の数が第2のより一貫して速いと思われる理由は明らかではないが、私は最適化されたコードは、意味のある方法でメソッドアクセスに対するフィールドを測定していることを疑う。)UPDATEDコード/結果再


JITコンパイラがループを最適化していることは明らかです。

+0

@Stephenはアクセサメソッドを使用してカプセル化を優先するだけでなく、速度も優先しますか?それは聞くのは素晴らしいことです!!! – Victor

+0

@Victor - 私はあなたがその結論を引き出すことができるとは思わない。確かに、私はあなたがこのベンチマークから**結論を引き出すことはできないと信じています。それは単に欠陥がある –

+0

スティーブンありがとう!私は...私はそれを考え始めた参照してください。だから、あなたがより柔軟なデザインを探している場合は、アクセサーメソッドを使用してスピードを使用して直接アクセスを求めるか? (offtopicの質問に申し訳ありません!) – Victor

関連する問題