谁能告诉我 Hotspot 或 Dalvik 是否足够聪明,可以内联调用返回常量(静态最终)int 值的最终方法?理想情况下,方法调用将被常量替换。这可能是在类加载时或通过 JIT。
这对我正在处理的一些代码的设计有影响。
谁能告诉我 Hotspot 或 Dalvik 是否足够聪明,可以内联调用返回常量(静态最终)int 值的最终方法?理想情况下,方法调用将被常量替换。这可能是在类加载时或通过 JIT。
这对我正在处理的一些代码的设计有影响。
我认为答案是“不,优化不会因为final
关键字的缺失或存在而发生”,至少在 HotSpot VM 上是这样。但是由于其他因素,优化可能会发生。
这是 Brian Goetz 在这篇文章中所说的(对不起,引述过长):
像许多关于 Java 性能的神话一样,错误地认为将类或方法声明为最终会导致更好的性能被广泛接受,但很少被检查。这个论点认为,将方法或类声明为 final 意味着编译器可以更积极地内联方法调用,因为它知道在运行时这绝对是要调用的方法的版本。但这根本不是真的。仅仅因为类 X 是针对最终类 Y 编译的,并不意味着将在运行时加载相同版本的类 Y。所以编译器不能安全地内联这样的跨类方法调用,不管是否是最终的。只有当方法是私有的时,编译器才能自由地内联它,在这种情况下,final 关键字将是多余的。
另一方面,运行时环境和 JIT 编译器有更多关于实际加载哪些类的信息,并且可以做出比编译器更好的优化决策。如果运行时环境知道没有加载扩展 Y 的类,那么它可以安全地内联对 Y 的方法的调用,无论 Y 是否是最终的(只要它可以使此类 JIT 编译的代码无效,如果 Y 的子类稍后加载)。所以现实情况是,虽然 final 可能是对不执行任何全局依赖分析的愚蠢运行时优化器的有用提示,但它的使用实际上并不能启用很多编译时优化,并且不需要智能JIT 执行运行时优化。
还有一篇很好的帖子为什么final 不再是 final 了,至少在 Java 5 中是这样。
或者,Soot有望针对这种情况优化 Java 字节码。
内联是 JIT 编译器在检测到热点时可能执行的操作,这是字节码中经常被调用的方法,可能值得花费一些 CPU 时间将字节码编译成机器码。
JIT 编译器很有可能会内联一个final
方法(因为它不能被覆盖)。如果该方法只返回一个常量值,机会会更好。
但这是我的理解 - 如果调用方法不是热点,那么它将不会被编译并且不会有final
方法的内联。
(德语信息来源)