如果大部分方法都是调用站点的死代码,java 可以内联一个大方法吗?

Mar*_* VY 4 java jit jvm jvm-hotspot compiler-optimization

我知道 Java HotSpot 用来决定一个方法是否值得内联的标准之一是方法的大小。一方面,这似乎是明智的:如果方法很大,内联会导致代码膨胀,并且该方法需要很长时间来执行,以至于调用开销是微不足道的。这种逻辑的问题在于,在您决定内联之后,很明显,对于这个特定的调用站点,大部分方法都是死代码。例如,该方法可能是一个巨大的 switch 语句,但大多数调用站点使用编译时常量调用该方法,因此实际上:内联很便宜(不需要整个方法体;最小的代码膨胀)并且有效(方法调用开销支配实际完成的工作)。

HotSpot 是否有任何机制来利用这种情况并无论如何内联方法,或者是否存在限制甚至拒绝考虑内联方法的限制,即使它具有最小的代码膨胀效应?

apa*_*gin 6

HotSpot JIT 内联策略相当复杂。它涉及许多启发式方法,如调用方方法大小、被调用方方法大小、IR 节点计数、内联深度、调用计数、调用站点计数等。

有一些硬性限制会阻止大型方法内联,包括:

  • -XX:FreqInlineSize=325 - 要内联的被调用者字节码的最大大小;
  • -XX:InlineSmallCode=2000 - 如果被调用者已经有至少这个字节大小的编译代码,则不要内联被调用者;
  • -XX:NodeCountInliningCutoff=18000 - 如果解析器生成此数量的 IR 节点,则停止内联;
  • -XX:DesiredMethodLimit=8000- 内联后聚合方法的最大字节码大小。此参数在 HotSpot 的产品版本中不可调整,但可以使用 关闭限制-XX:-ClipInlining

还有其他限制,但正如您已经看到的,大型方法没有太多机会被内联,即使-XX:+IncrementalInline默认情况下是启用的。