【发布时间】:2019-07-08 09:13:21
【问题描述】:
来自 C/C++ 的人提出的基本性能问题。
我正在使用一个集合 (ArrayDeque) 来简单地按身份保存、添加、删除项目。我知道合同是让集合在检查相等性时使用equals(),例如在remove(obj) 期间,但在我的情况下,我想使用引用语义(如 IdentityHashMap 但不需要地图)。所以我很高兴知道我永远不会覆盖集合中保存的任何对象(声明为保存接口)上的equals()。
来自本机编程的我不禁问自己,remove(obj) 的编译代码是否会遍历项目并在 Object.equals() 上执行 虚拟调用 只是为了比较地址?由于我正在存储接口引用,因此无法(?)使用final 优化它,因此编译器不会费心进行无用的调用(即内联它们) - 但现在我领先于自己,因为它可能无论如何都不需要这种优化,并且 JVM 有其他方法(去虚拟化?)在这种情况下生成最佳代码。
假设我的代码需要首先考虑这方面可以获得的优化级别 - 我的理解正确吗?这种情况下有什么好的设计?
【问题讨论】:
-
如果重复调用
Object::equals,JIT 编译器会内联您的调用 ==> 不要打扰。 -
@assylias 但这很棘手,对吧?就编译器所知,该集合可能包含多个派生最多的类实例,其中一些可能会覆盖
equals(),而另一些则不会。因此,不可能生成不会单独查看每个项目的代码 - 内联需要一个需要在编译时表达的假设 -
内联确实需要 JVM 的编译时假设 - 这是 JIT 编译的重点:它使用运行时可用的所有信息。您可以使用以下选项运行程序以查看该方法是否以及何时内联:
-XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining -
我的意思是,我确定你看到了,是“不需要内联”,呵呵。
-
Java 的整体理念是您不需要关心这些细节。我猜你所说的 virtual call 是指传统的 C++ 风格。 Here are the (quite overwhelming and startling) low-level details.
标签: java performance collections equals identity