简体   繁体   English

吸气剂是否对Java性能不利?

[英]Are getters bad for performance in Java?

Given the following two code options, is there any performance benefit (over a very large scale or a long period of time) of the second over the first? 给定以下两个代码选项,与第一个相比,第二个代码在性能上有很大的好处吗(在非常大的规模或很长的一段时间内)?

Option 1 选项1

private Map<Long, Animal> animals = ...;
public Map<Long, Animal> getAnimals() {
    return animals;
}

public void useAnimals() {
    for (int i=0; i < SOME_LARGE_NUMBER; i++) {
        Animal animal = getAnimals().get(id);
    }
    // Many many calls to getAnimals() are made...
}

Option 2 - no getter 选项2-无吸气剂

private Map<Long, Animal> animals = ...;

public void useAnimals() {
    for (int i=0; i < SOME_NUMBER; i++) {
        Animal animal = animals.get(id);
    }
    // No method calls made
}

If it is bad for performance, why, and how should I determine whether it is worth mitigating? 如果对性能不利,为什么?如何确定它是否值得缓解?

And, would storing the result of getAnimals() as a local provide a benefit... 并且,将getAnimals()的结果存储为本地会带来好处...

  • if SOME_NUMBER is hundreds or thousands? SOME_NUMBER是几百还是几千?
  • if SOME_NUMBER is only in the order of magnitude of 10? 如果SOME_NUMBER的数量级仅为10?

Note : I previously said "encapsulation". 注意 :我之前说过“封装”。 I changed it to "getter" because the purpose is actually not that the field can't be modified but that it can't be reassigned. 我将其更改为“ getter”,因为实际上的目的不是要修改字段,而是不能重新分配字段。 The encapsulation is simply to remove responsibility for assignment from subclasses. 封装只是为了消除子类分配的责任。

Most likely JVM will inline getAnimals() invocation in tight loop effectively falling back to Option 1 . JVM最有可能在紧密循环中内联getAnimals()调用,从而有效地退回到Option 1 So don't bother, this is really a micro (nano?) optimization. 因此,不要打扰,这实际上是一个微(纳米)优化。

Another thing is migrating from field access to local variable. 另一件事是从字段访问迁移到局部变量。 This sounds good since instead of traversing through this reference every time you always have a reference on the stack (two memory accesses vs. one). 这听起来不错,因为不必每次都在堆栈上始终有一个引用时遍历this引用(两个内存访问相对于一个)。 However I believe (correct me if I'm wrong) that since animals is private and non- volatile again JVM will perform this optimization for you at runtime. 但是,我相信(如果我错了,请纠正我),由于animals是私有的并且是非易失volatile ,JVM将在运行时为您执行此优化。

The second snippet is more encapsulated than the first one. 第二个摘要比第一个摘要封装得更多 The first one gives access to the internal map to anyone, whereas the second keeps it encapsulated in the class. 第一个将任何人都可以访问内部映射,而第二个将其封装在类中。

Both will lead to comparable performance. 两者都会带来可比的性能。

EDIT: since you change the question, I'll also change the answer. 编辑:由于您更改了问题,我也会更改答案。

If you go through a getter, and the getter is not final, it means that subclasses may return another map than the one you hold in the class. 如果您经历了一个吸气剂,而该吸气剂不是最终的,则意味着子类可能返回与您在类中持有的映射不同的另一种映射。 Choose whether you want your method to operate on the subclass's map or on the class's map. 选择您要让方法在子类的地图上还是在类的地图上进行操作。 Both could be acceptable, depending on the context. 两者都可以接受,具体取决于上下文。

Anyway, suppose your subclass always makes a defensive copy of the map, you'll end up having many copies if you don't cache the result of the getter in a local variable of useAnimals . 无论如何,假设您的子类总是制作地图的防御性副本,如果您不将getter的结果缓存在useAnimals的局部变量中,最终将拥有许多副本。 It might be required to always work on the latest value of the subclass's map, but I doubt it's the case. 可能需要始终处理子类映射的最新值,但我怀疑情况确实如此。

If there is no subclass, or the subclass doesn't override the method, or override it by always returning the same map, both will lead to comparable performance and you shouldn't care about it. 如果没有子类,或者子类没有重写该方法,或者不通过始终返回相同的映射来重写该方法,则两者都将导致可比的性能,因此您无需理会。

Have you profiled this to see if it matter, for a modern JIT I would guess it would get optomized away, especially if animals was marked final but there is nothing stopping you from testing this yourself. 您是否配置了此文件以查看是否重要,对于现代JIT,我它会受到影响,特别是如果将animals标记为final animals ,但是没有什么阻止您自己对此进行测试。

Either way, I am 100% this would NEVER be your bottle neck in an application. 无论哪种方式,我都100% 决不成为您在应用程序中的瓶颈。

Well, I don't think that JVM will inline the function call. 好吧,我认为JVM不会内联函数调用。 So probably it may affect performance. 因此可能会影响性能。 The better way is to create local variable and assign class field animals to it. 更好的方法是创建局部变量并为其分配类字段动物。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM