Java 优化:(Hotspot/Dalvik)优化返回常量的 final 方法?

6

有人能告诉我Hotspot或Dalvik是否足够智能,可以内联调用返回常量(static final)int值的最终方法吗?理想情况下,方法调用将被常量替换。这可能是在类加载时还是通过JIT完成。

这对我正在工作的某些代码的设计有影响。


6
为什么这样一种透明的微优化会影响你的设计? - JB Nizet
1
java -XX:+PrintOptoAssembly 可以帮助您找到。 - Op De Cirkel
1
我正在尝试与特定类型的每个子类共享单个(常量)值,因此重载受保护的访问器方法来实现,而不是提供给构造函数存储在父类定义的字段中。额外的开销对使用非常重要。 - Mark Renouf
3个回答

13
我认为答案是“不会,因为有或没有final关键字而进行的优化不会发生”,至少在HotSpot VM上是这样。但是由于其他因素,优化很可能会发生。
以下是Brian Goetz在这篇文章中的说法(引用如下):
像许多关于Java性能的误解一样,将类或方法声明为final会导致更好的性能这个错误的观点广为流传,但很少被检查。论据是将方法或类声明为final意味着编译器可以更积极地内联方法调用,因为它知道在运行时这绝对是要调用的方法版本。但这不是真的。只是因为X类是针对final类Y编译的,并不意味着在运行时将加载相同版本的Y类。因此,编译器不能安全地内联这类跨类方法调用,无论是否使用了final关键字。只有方法是私有的时候,编译器才能自由地内联它,在那种情况下,final关键字是多余的。
另一方面,运行时环境和JIT编译器拥有更多关于哪些类实际上已加载的信息,并且可以比编译器更好地做出优化决策。如果运行时环境知道没有加载扩展Y的类,那么它可以安全地内联对Y的方法的调用,无论Y是否被声明为final(只要它可以在稍后加载Y的子类时使这种JIT编译的代码无效)。因此,现实情况是,虽然final可能是一个有用的提示对于一个不执行任何全局依赖关系分析的愚蠢运行时优化器,但其使用并没有实际启用很多编译时优化,并且智能JIT执行运行时优化时也不需要。

这里也有一篇很好的文章解释了为什么在Java 5中,final已经不再是最终的了


1
这句话并没有说JIT不会内联final方法。它说即使方法不是final,JIT也可以内联方法,并且使用final关键字并不需要获得此优化。 - JB Nizet
1
据我理解你引用的内容,优化很可能会发生。但最终结果或多或少是无用的。 - Op De Cirkel
是的,我也明白优化可能会发生 - 但不是因为final字段的存在或缺失。澄清了答案。 - mindas

0

内联是JIT编译器在检测到热点时可能会执行的操作,即在字节码中被频繁调用的方法值得花费一些CPU时间将其编译成机器码。

JIT编译器很有可能会内联一个final方法(因为它不能被覆盖)。如果该方法只返回一个常量值,则成功率会更高。

但据我所知,如果调用方法不是热点,则不会被编译,也不会内联final方法。

(德语信息来源)


0

或者,Soot 预计可以优化 Java 字节码以适应这种情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接