OpenJDK 17.0.8 增强功能:
- 包括一个新功能(请参阅JDK-8287061和JDK-8289943),通过增加标量替换的机会数量来提高逃逸分析的性能。现在默认启用此功能。要禁用它,开发人员必须使用以下 JVM 标志:
-XX:-ReduceAllocationMerges
逃逸分析(转义分析)
逃逸分析是一个分析过程。它检测对象在编译单元外部是否可见。
通过返回或作为参数传递给另一个方法,对象可以在编译单元外部变得可见,或写入字段。
聚合的标量替换使用转义分析的结果,并适用于未转义编译单元或仅在某些分支上转义的对象。它用简单值(标量)替换对象(聚合),其效果与局部变量类似。
逃逸分析确定可以存储对象的所有位置,
以及是否可以证明对象的生命周期仅限于当前方法和/或线程。
但是,标量替换确实是一种你永远无法绝对确定的优化,因为它取决于太多因素。
- 首先,只有当实例的所有使用都内联在一个编译单元中时,才可以消除分配。然而,内联本身在 HotSpot 中是一种脆弱的优化,因为它依赖于许多启发式方法和限制。
- 其次,如果引用有条件地接收不同的值,则不会发生标量替换。
另一篇推荐阅读的文章是 Aleksey Shipilёv 的博客文章,其中还演示了如何使用JMH来验证标量替换是否在特定场景中发生。
网友建议:
- 除非您是性能专家(其实很难),否则不要假设哪种代码性能良好或性能较差,并在分析探查器报告时保持怀疑态度。这不是特别有用的建议(它归结为:分析器报告可能在骗你!),但事实就是如此。实际上,要么成为性能专家,要么接受对此无能为力的事实。
- 编写惯用的 java 代码。它最容易维护并且最有可能通过热点进行优化。
- 降低算法复杂性是有用的,并且应该始终是您检查的第一件事。在某种程度上,降低算法复杂性的优化会忽略第一条规则。您不需要特别了解 JVMTI 或 Flight Recorder 的变幻莫测以及分析器的工作原理,就可以得出算法重写是值得的并且将显着提高性能的结论。
- 不要相信简洁的经验法则,无论有多少人这么说。不要寻找“易于应用的模式”,例如“通过附加先测试空的 if 块来替换所有 foreach 循环”——这些本质上永远不会正确,并且通常会降低性能。