Java:Getter和setter比直接访问更快?

Mr.*_*eah 22 java performance getter-setter

我测试了我在Linux上网本上使用VisualVM 1.3.7 编写的Java光线跟踪器的性能.我用剖面仪测量.
为了好玩,我测试了使用getter和setter以及直接访问字段之间的区别.getter和setter是标准代码,没有添加.

我没想到会有任何分歧.但直接访问代码的速度较慢.

这是我在Vector3D中测试的样本:

public float dot(Vector3D other) {
    return x * other.x + y * other.y + z * other.z;
}
Run Code Online (Sandbox Code Playgroud)

时间:1542毫秒/ 1,000,000次调用

public float dot(Vector3D other) {
    return getX() * other.getX() + getY() * other.getY() + getZ() * other.getZ();
}
Run Code Online (Sandbox Code Playgroud)

时间:1453毫秒/ 1,000,000次调用

我没有在微基准测试中测试它,而是在光线跟踪器中测试.我测试代码的方式:

  • 我用第一个代码启动了程序并进行了设置.光线跟踪器尚未运行.
  • 我启动了探查器并在初始化完成后等了一会儿.
  • 我开始了一个光线追踪器.
  • 当VisualVM显示足够的调用时,我停止了探查器并等了一会儿.
  • 我关闭了光线追踪程序.
  • 我用第二个代码替换了第二个代码,并在编译后重复上述步骤.

我至少为这两个代码运行了20,000,000次调用.我关闭了任何我不需要的程序.我设置CPU的性能,所以我的CPU时钟是最大的.每时每刻.
第二个代码如何快6%?

Boh*_*ian 29

我做了一些微型基准测试,大量的JVM热身,发现这两种方法的执行时间完全相同.

发生这种情况是因为JIT编译器在getter方法中嵌入了对字段的直接访问,从而使它们成为相同的字节码.

  • 我没看.我猜测了.JIT对最小等效代码进行内联,重写等,在简单的getter的情况下,用直接字段访问代替.我收集的时间证据表明,两者的相同之处都是相同的,因此合乎逻辑的结论是吸气剂已经被直接场访问所取代. (3认同)
  • +1表示编译器字节码优化 (2认同)
  • @ Mr.Yeah你看过类文件中编译的字节ode,我不是在谈论,或者是JIT编译器替换编译后的字节代码的新内存代码(我不确定你能不能甚至到)? (2认同)

Mr.*_*eah 13

谢谢大家帮我回答这个问题.最后,我找到了答案.

首先,波希米亚是正确的:使用PrintAssembly,我检查了生成的汇编代码是相同的假设.是的,虽然字节码不同,但生成的代码是相同的.
所以masterxilo是对的:探查器必须是罪魁祸首.但是masterxilo对时序栅栏和更多仪器代码的猜测并不属实; 两个代码最终都是相同的.

所以还有一个问题:第二个代码在Profiler中的速度有多快6%?

答案取决于VisualVM如何测量:在开始分析之前,您需要校准数据.这用于消除分析器导致的开销时间.
虽然校准数据是正确的,但测量的最终计算不是.VisualVM在字节码中看到方法调用.但它没有看到JIT编译器在优化时删除了这些调用.
因此它消除了不存在的开销时间.这就是差异的出现方式.