4.8 小结

本节提供了大量关于即时编译如何工作的细节。从调优角度看,简单的选择就是对所有应用都使用 server 编译器和分层编译,这将解决 90% 的与编译器相关的性能问题。只要确保代码缓存足够大,编译器就能提供尽善尽美的性能。

关于编译器调优的最后一句话

如果你有 Java 性能调优方面的经验,你或许会觉得惊奇,因为整章关于编译的讨论中都没有提及 final 关键字。final 总被认为是影响性能的重要因素,因为大家相信在进行内联和其他优化时,final 可以使 JIT 编译器作出更好的选择。

这种想法在落伍的过去或许有一些价值,但已经很多年很多年不是这样了(即便曾经是)。而其实它是流传甚广的谣言。准确地说,只要有必要时,你就应该使用 final:比如你不打算改变的不可变对象或原生值,内部类引用的外部参数等等。但无论有没有 final 关键字,都不会影响应用的性能。

本章也包括了大量关于编译器如何运作的背景知识。这么做的原因是,你可以理解第 1 章关于小方法和小代码的一般性建议,以及第 2 章所描述的微基准测试对编译器的影响。特别是,还涵盖了以下知识。

(1) 不用担心小方法——特别是 getter 和 setter,因为它们很容易内联。如果你觉得某个方法的负载过大,那你可能只是在理论上是正确的(通过移除内联给性能造成的巨大影响可以展示这点)。而实际上并不是这样,因为编译器会修复这些问题。

(2) 需要编译的代码在编译队列中。队列中代码越多,程序达到最佳性能的时间越久。

(3) 虽然代码缓存的大小可以(也应该)调整,但它仍然是有限的资源。

(4) 代码越简单,优化越多。分析反馈和逃逸分析可以使代码更快,但复杂的循环结构和大方法限制了它的有效性。

最后,如果你在分析代码时,很惊奇地发现一些方法出现在了分析信息的顶部——你原本期望不应该出现在那里——你可以使用本章的内容审视编译器正在做什么,以确保它正在以你所写的代码逻辑处理。