Java 为什么JVM有一个最大的内联深度?
Java 为什么JVM有一个最大的内联深度?,java,jvm,jit,Java,Jvm,Jit,java有一个参数-XX:MaxInlineLevel(默认值为9),用于控制内联的最大嵌套调用数。为什么会有这样的限制?为什么基于频率和代码大小的常规启发式不足以让JVM自行决定内联的深度 (这是因为我看到一个嵌套很深的番石榴checkArgument调用由于深度原因没有内联)一些重要的搜索发现了这个有趣的小问题(我实际上已经找到了谷歌搜索的4): 这表明MaxInlineLevel与预期一样是一个硬限制,限制了在停止内联之前的深度。它还建议MaxRecursiveInlineLevel仅指直
java
有一个参数-XX:MaxInlineLevel
(默认值为9),用于控制内联的最大嵌套调用数。为什么会有这样的限制?为什么基于频率和代码大小的常规启发式不足以让JVM自行决定内联的深度
(这是因为我看到一个嵌套很深的番石榴
checkArgument
调用由于深度原因没有内联)一些重要的搜索发现了这个有趣的小问题(我实际上已经找到了谷歌搜索的4):
这表明MaxInlineLevel
与预期一样是一个硬限制,限制了在停止内联之前的深度。它还建议MaxRecursiveInlineLevel
仅指直接递归调用,而不是相互递归调用,例如foo()
调用bar()
调用foo()
因此,我认为我的猜测是正确的-MaxInlineLevel
是为了防止相互递归,因为要检测到需要保留对内联调用堆栈全部深度的引用
MaxInlineResursionLevel
控制foo()
调用foo()
内联
请注意,引用的代码可能不是真正的JVM
@apangin在OpenJDK8中找到了一个更现代的hotspot版本,这表明它现在已经不再那么简单了。看起来整个堆栈都在搜索递归调用,所以现在可能会阻止相互递归通过
MaxRecursiveInlineLevel
一点也不确定,但可能是为了避免相互递归陷阱,而这种陷阱可能很难/昂贵地用其他方式进行防御。@OldCurmudgeon但是你有MaxRecursiveInlineLevel@MrSimpleMind-有趣-因此,我显然错了。一定是别的原因。你看看那些非常古老的资料。正确的位置在MaxRecursiveInlineLevel
对两个递归调用进行计数。@apangin-这似乎不像注释所说的那样。此外,它仅与MaxRecursiveInlineLevel
进行比较。很好的发现,深入挖掘。遍历所有帧,查看被调用方方法是否出现在堆栈上的任何位置。现在设置在InlineTree构造函数中。@apangin,也许你知道这个问题的正确答案?@TagirValeev不完全正确,但我想基本原因是保持简单。无限的内联深度会增加复杂性,编译时间和内存使用可能不太可预测(这对于AOT编译器来说是可以的,但对于JIT来说不是)。还要记住,编译后的代码应该在运行时跟踪整个内联树(以便能够展开和取消优化)。虽然我认为默认值9已经过时了。它已经很久没有改变了,但是现在,有了更多的可用资源,考虑到streams和lamdas,肯定有改进的地方。
if (inline_depth() > MaxInlineLevel) {
return "inlining too deep";
}
if (method() == callee_method
&& inline_depth() > MaxRecursiveInlineLevel) {
return "recursively inlining too deep";
}