在 Java 中,通过 getter 引用字段与通过变量引用字段之间是否存在性能差异?
-
20-09-2019 - |
题
这样做有什么区别吗
Field field = something.getSomethingElse().getField();
if (field == 0) {
//do something
}
somelist.add(field);
相对
if (something.getSomethingElse().getField() == 0) {
//do something
}
somelist.add(something.getSomethingElse().getField());
通过 getter 引用该字段是否会导致性能损失,或者与引用已分配的变量相同吗? 我知道变量只是对内存空间的引用,因此 getter 应该只是获取该内存空间的另一种方式。
请注意,这是一个学术问题(只是出于好奇)而不是一个实际问题。
解决方案
假设getSomethingElse()
被定义为
public SomethingElse getSomethingElse() {
return this.somethingElse;
}
性能差异将是最小的(或零,如果它会得到内联)。然而,在现实生活中你不能总是肯定是这样的话 - 可能会有一些处理发生在幕后(在对象本身,但是,说不一定,通过AOP代理)。所以结果保存在重复访问的变量可以是一个好主意。
其他提示
这是可忽略的不利。不要用它关心自己太多,否则你会堕入过早的优化。如果你的应用是缓慢的,这不是原因所在。
有在一个方法调用通过吸气导致在访问变量的差。在JVM可以设想能够优化方法调用远在某些情况下,但它的是一个方法调用。
这是说,如果你的代码的最大瓶颈或性能问题,从访问方法是开销,我会说,你没有很多的担心。
有是性能上的损失(其可以是如此之小,可以忽略不计)然而,JVM可以内联这个和所有的呼叫,以改善性能。
如果你把它的第二种方式会更好。
不,如果你有一个很好的JVM,如热点从Sun它将线和编译(为本地代码)的吸气剂。
使用吸气剂通常非常好的实践中,作为防御措施,和一般的信息隐藏。
如果使用Java编写Android应用程序需要注意的一点是在这里: http://developer.android.com/training/articles/perf-tips html的#GettersSetters
在像C母语++是很常见的做法是使用吸气剂(I = getCount将()),而不是直接访问场(I = mCount)。这个 为C ++优异的习惯,并且通常在其它对象实践 导向语言,如C#和Java,因为编译器通常可以 内联访问,如果你需要限制或调试现场访问 可以在任何时间添加代码。
<强>然而,这是在Android一个好主意。强>虚拟方法调用 价格昂贵,远远超过了实例字段查找。这是合理的 按照通用的面向对象编程实践和有 一个类中的getter和公共接口制定者,但你 应该总是直接访问字段。
如果没有一个JIT,直接字段访问为约3倍比调用更快 琐碎的getter。随着JIT(其中直接字段访问是便宜 访问本地),的直接字段访问为约7倍的速度比 调用一个微不足道的吸气剂。强>
请注意,如果你使用ProGuard,你可以有两全其美 世界因为ProGuard的可以内联存取你。
如果该方法是一个简单的吸气没有处理涉及它不是一个问题。如果涉及大量的计算,属性不会做你想要的要多。
在唯一一次我会担心任何区别与迭代(数以千计)的数量庞大的紧密循环。即使那么这可能是唯一的,如果你正在使用方面编织额外的处理(例如日志)的问题,这可能涉及数以千计的创建额外的对象(如JoinPoints和参数自动装箱)和由此产生的GC问题。
我就不会担心的性能差异。你会最好不要去想它,而是把时间花在现实情景中的剖析你的代码。你很可能会发现,你的程序的缓慢部分是不是你认为他们是。
这篇文章讨论的是 CLI VM 而不是 JVM,但每个虚拟机都能够做类似的事情,所以我相信它是相关的。
我正在以一种特殊的方式为我的 JIT 处理这个特殊问题。请注意,此处的描述是概念性的,出于性能原因,代码以略有不同的方式实现它。当我加载程序集时,如果它仅返回成员字段,我会在方法描述符中进行注释。当我稍后 JIT 其他方法时,我会替换所有 call
字节码中这些方法的指令带有 ldfld
指令,然后将其传递给本机代码生成器。通过这种方式,我可以:
- 节省 JIT 时间(
ldfld
JIT 所需的处理器时间比call
). - 内联属性甚至在 基线编译器.
- 总的来说,当调试器分离时,使用公共属性/私有字段模式不会导致任何类型的性能损失。(附加调试器后,我无法内联访问器。)
我毫不怀疑虚拟机技术领域的知名人士已经在他们的产品中实现了与此类似(并且可能比此更好)的功能。