【问题标题】:Why does the JVM have a maximum inline depth?为什么JVM有最大内联深度?
【发布时间】:2015-09-10 13:46:21
【问题描述】:

java 有一个参数-XX:MaxInlineLevel(默认值为 9),它控制对内联的嵌套调用的最大数量。为什么会有这样的限制?为什么通常的基于频率和代码大小的启发式方法不足以让 JVM 自行决定内联的深度?

(这是由 JitWatch 提示的,它向我展示了深层嵌套的 Guava checkArgument 调用由于深度而没有被内联)

【问题讨论】:

  • 完全不确定,但可能是为了避免相互递归陷阱,这些陷阱可能难以/昂贵地以其他方式防御。
  • @OldCurmudgeon 但是你有 MaxRecursiveInlineLevel
  • @MrSimpleMind - 有趣 - 因此我显然错了。一定是其他原因。

标签: java jvm jit


【解决方案1】:

一些重要的搜索发现了这个有趣的小fragment(实际上我已经到了 Google 搜索的第 4 页):

    if (inline_depth() > MaxInlineLevel) {
        return "inlining too deep";
    }
    if (method() == callee_method
            && inline_depth() > MaxRecursiveInlineLevel) {
        return "recursively inlining too deep";
    }

这表明MaxInlineLevel 是对停止内联之前的深度的硬性限制。它还表明MaxRecursiveInlineLevel 仅指直接递归调用,而不是相互递归调用,例如foo() 调用bar() 调用foo()

所以我认为我的猜测评论是正确的 - MaxInlineLevel 是为了防止 相互 递归,因为检测到您需要保留对内联调用堆栈的完整深度的引用。

MaxInlineResursionLevel 控制 foo() 调用 foo() 内联。

请注意,引用的代码可能不是真正的 JVM。

@apangin 的评论从 Open JDK 8 中找到了一个更现代的热点版本,这表明它现在不再那么简单了。看起来整个堆栈都在搜索递归调用,因此现在也可能会阻止相互递归通过MaxRecursiveInlineLevel

【讨论】:

  • 您查看非常古老的资源。正确的地方是hg.openjdk.java.netMaxRecursiveInlineLevel 计算 direct and indirect 递归调用。
  • @apangin - 这似乎不像评论所说的那样。此外,它仅与MaxRecursiveInlineLevel 进行比较。不过很好找。
  • 深入挖掘。 The loop 遍历所有帧,查看被调用者方法是否出现在堆栈的任何位置。 MaxInlineLevel 现在在 InlineTree 构造函数中设置。
  • @apangin,你可能知道这个问题的正确答案吗?
  • @TagirValeev 不完全是,但我想基本原因是为了保持简单。无限的内联深度会增加复杂性,编译时间和内存使用可能不太可预测(这对于 AOT 编译器是可以的,但对于 JIT 则不行)。另请注意,编译后的代码应在运行时跟踪整个内联树(以便能够展开和取消优化)。虽然我认为默认值 9 已经过时。它已经很久没有改变了,但是现在,有了更多的可用资源,考虑到流和 lamdas,肯定有改进的地方。
猜你喜欢
  • 2015-01-08
  • 1970-01-01
  • 2020-07-06
  • 2022-10-05
  • 2018-08-19
  • 2014-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多