2013-02-12 62 views
6

我正在做一些测试,以找出使用getters/setters和直接字段访问之间的速度差异。我写了一个简单的基准测试应用程序是这样的:为什么Method访问看起来比Field访问更快?

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次迭代执行得非常快。


编辑:经考虑assyliasStephen C意见,我已经改变了代码http://pastebin.com/Vzb8hGdc那里我得到了略有不同的结果:http://pastebin.com/wxiDdRix

+2

我认为编译器内联了getters。你检查过字节码吗? – jlordo 2013-02-12 11:57:09

+10

'/ *等待VM预热*/Thread.sleep(1000);' - 这不是它的工作原理。如果JVM没有做任何事情,它就不会升温......你的微基准有几个缺陷。特别是:(i)您并不真正允许JVM进行预热(ii)您要测试的两个路径采用相同的方法,这可能会阻止某些优化。 – assylias 2013-02-12 11:58:53

+11

@jlordo - 内联由JIT编译器完成。我将不会在字节码中看到。 – 2013-02-12 11:59:12

回答

9

解释是你的基准已经坏了。

第一次迭代是使用解释器完成的。

Field Access: 1528500478 ns 
Method Access: 1521365905 ns 

第二次迭代由解释器完成,然后我们翻转到运行JIT编译代码。

Field Access: 1550385619 ns 
Method Access: 47761359 ns 

其余的迭代都是使用JIT编译代码完成的。

Field Access: 68 ns 
Method Access: 33 ns 

etcetera 

的原因,他们难以置信快JIT编译器已经优化环路走。它发现它们没有为计算提供任何有用的东西。 (目前尚不清楚为什么第一数目似乎一致地比第二快,但我怀疑优化的代码测量场与任何有意义的方式方法的访问。)


的Re 修订代码/结果:很明显,JIT编译器仍在优化循环。

+0

因此,@Stephen使用访问器方法不仅有利于封装,它也有利于速度?听到这个消息我很高兴!!! – Victor 2014-05-29 13:21:36

+0

@Victor - 我不相信你可以得出这个结论。事实上,我不认为你可以从这个基准测试中得出任何**结论。这是简单的瑕疵 – 2014-05-29 16:24:51

+0

谢谢斯蒂芬!我明白......我开始这么想。所以,如果你寻求速度使用直接访问,如果你看起来更加灵活的设计,使用访问器的方法? (对不起这个偏题的问题!) – Victor 2014-05-29 16:34:54