java 如果大部分方法在调用点都是死代码,能否内联一个大方法?
Can java inline a large method if the most of it would be dead code at the call site?
我知道 Java HotSpot 用来决定一个方法是否值得内联的标准之一是该方法有多大。一方面,这似乎是明智的:如果方法很大,内联会导致代码膨胀,并且该方法将花费很长时间来执行,以至于调用开销微不足道。这种逻辑的问题在于,在您决定内联之后,很明显对于这个特定的调用站点,大部分方法都是死代码。例如,该方法可能是一个巨大的 switch 语句,但大多数调用站点使用编译时常量调用该方法,因此实际上:内联很便宜(不需要整个方法体;最小的代码膨胀)并且有效(方法调用开销支配实际完成的工作)。
HotSpot 是否有任何机制来利用这种情况并无论如何内联该方法,或者是否有一个限制,超过这个限制它甚至拒绝考虑内联一个方法,即使它会产生最小的代码膨胀效应?
HotSpot JIT 内联策略相当复杂。它涉及许多启发式方法,如调用方方法大小、被调用方方法大小、IR 节点数、内联深度、调用数、调用点数等。
有一些硬限制阻止大型方法内联,包括:
-XX:FreqInlineSize=325
- 要内联的被调用者字节码的最大大小;
-XX:InlineSmallCode=2000
- 如果被调用者已经有至少这个字节大小的编译代码,则不要内联被调用者;
-XX:NodeCountInliningCutoff=18000
- 如果解析器生成此数量的 IR 节点,则停止内联;
-XX:DesiredMethodLimit=8000
- 内联后聚合方法字节码的最大大小。此参数在 HotSpot 的产品构建中不可调整,但可以使用 -XX:-ClipInlining
. 关闭限制
还有其他限制,但正如您已经看到的,即使 -XX:+IncrementalInline
默认启用,大型方法也没有太多机会被内联。
我知道 Java HotSpot 用来决定一个方法是否值得内联的标准之一是该方法有多大。一方面,这似乎是明智的:如果方法很大,内联会导致代码膨胀,并且该方法将花费很长时间来执行,以至于调用开销微不足道。这种逻辑的问题在于,在您决定内联之后,很明显对于这个特定的调用站点,大部分方法都是死代码。例如,该方法可能是一个巨大的 switch 语句,但大多数调用站点使用编译时常量调用该方法,因此实际上:内联很便宜(不需要整个方法体;最小的代码膨胀)并且有效(方法调用开销支配实际完成的工作)。
HotSpot 是否有任何机制来利用这种情况并无论如何内联该方法,或者是否有一个限制,超过这个限制它甚至拒绝考虑内联一个方法,即使它会产生最小的代码膨胀效应?
HotSpot JIT 内联策略相当复杂。它涉及许多启发式方法,如调用方方法大小、被调用方方法大小、IR 节点数、内联深度、调用数、调用点数等。
有一些硬限制阻止大型方法内联,包括:
-XX:FreqInlineSize=325
- 要内联的被调用者字节码的最大大小;-XX:InlineSmallCode=2000
- 如果被调用者已经有至少这个字节大小的编译代码,则不要内联被调用者;-XX:NodeCountInliningCutoff=18000
- 如果解析器生成此数量的 IR 节点,则停止内联;-XX:DesiredMethodLimit=8000
- 内联后聚合方法字节码的最大大小。此参数在 HotSpot 的产品构建中不可调整,但可以使用-XX:-ClipInlining
. 关闭限制
还有其他限制,但正如您已经看到的,即使 -XX:+IncrementalInline
默认启用,大型方法也没有太多机会被内联。