【问题标题】:java PrintCompilation output: what's the meaning of "made not entrant" and "made zombie"java PrintCompilation 输出:“made not entrant”和“madezombie”是什么意思
【发布时间】:2011-02-25 05:28:02
【问题描述】:

在运行 Java 1.6 (1.6.0_03-b05) 应用程序时,我添加了 -XX:+PrintCompilation 标志。在某些方法的输出中,尤其是我知道的一些方法被调用很多时,我看到了 made not entrantmade zombie 文本。

这些是什么意思?最好的猜测是,在重新编译该方法或具有更大优化的依赖项之前,这是一个反编译步骤。真的吗?为什么是“僵尸”和“进入者”?

例如,其中一些行之间有相当长的时间:

[... near the beginning]
42       jsr166y.LinkedTransferQueue::xfer (294 bytes)

[... much later]
42    made not entrant  jsr166y.LinkedTransferQueue::xfer (294 bytes)
---   n   sun.misc.Unsafe::compareAndSwapObject
170       jsr166y.LinkedTransferQueue::xfer (294 bytes)
170   made not entrant  jsr166y.LinkedTransferQueue::xfer (294 bytes)
  4%      jsr166y.LinkedTransferQueue::xfer @ 29 (294 bytes)
171       jsr166y.LinkedTransferQueue::xfer (294 bytes)

[... even later]
42    made zombie  jsr166y.LinkedTransferQueue::xfer (294 bytes)
170   made zombie  jsr166y.LinkedTransferQueue::xfer (294 bytes)
171   made not entrant  jsr166y.LinkedTransferQueue::xfer (294 bytes)
172       jsr166y.LinkedTransferQueue::xfer (294 bytes)

[... no further logs]

【问题讨论】:

    标签: java jit jvm-hotspot


    【解决方案1】:

    这绝对不是我的专业领域,但我很感兴趣,所以做了一些挖掘。

    您可能会发现一些有趣的链接:OpenJDK:nmethod.cppOpenJDK:nmethod.hpp

    摘录nmethod.hpp

    // Make the nmethod non entrant. The nmethod will continue to be
    // alive.  It is used when an uncommon trap happens.  Returns true
    // if this thread changed the state of the nmethod or false if
    // another thread performed the transition.
    bool  make_not_entrant() { return make_not_entrant_or_zombie(not_entrant); }
    //...
    

    只是作为一个起点。

    【讨论】:

    • 这是一个有用的开始,谢谢。我越是查看代码,发现我不知道的热点词汇就越多!那么我们是否认为“not_entrant”只是意味着“不要再次执行此编译代码,需要先取消选择/重新编译”?另一个链接:见google.com/codesearch/p?hl=en#aRIt9pqzOVI/src/share/vm/oops/…的第536行
    • 鉴于“进入”的含义,我的猜测将是它标记已编译的方法不会再次进入(尽管某些线程可能仍然be in it) 而zombie则意味着它没有进一步的用途并且可以被处理掉。就像收银台可以宣布它不接受新客户(非进入者),但仍然必须在关闭收银台(僵尸)之前为排队的客户提供服务。但这只是猜测。
    【解决方案2】:

    我在my blog 上收集了一些关于此的信息。我发现的一条 Cliff Click 评论说:

    僵尸方法是其代码因类加载而无效的方法。通常,服务器编译器会对非最终方法做出积极的内联决策。只要内联方法从未被覆盖,代码就是正确的。当一个子类被加载并且方法被覆盖时,编译后的代码会被中断,以供将来调用它。代码被声明为“不可进入”(没有未来的调用者对损坏的代码),但有时现有的调用者可以继续使用该代码。在内联的情况下,这还不够好;当现有调用者的堆栈帧从嵌套调用返回到代码时(或者仅当它们在代码中运行时),它们的堆栈帧将被“取消优化”。当没有更多的堆栈帧将 PC 保存到损坏的代码中时,它就被宣布为“僵尸”——一旦 GC 处理它,就可以将其移除。

    【讨论】:

    【解决方案3】:

    Here is a GistPrintCompilation 上提供了令人难以置信的大量信息。具体来说,它说:

    当去优化发生时,如果决定使违规的nmethod失效,将首先“设为不可进入”;然后,当NMethodSweeper 发现堆栈上不再有它的激活时,它是“僵尸”;

    【讨论】:

      【解决方案4】:

      较新的解释是日志中可以有这样的条目:

      129   72       3       EscapeAnalysysTest::second (24 bytes)
      .......... some more lines
      135   76       4       EscapeAnalysysTest::second (24 bytes)
      137   74       3       EscapeAnalysysTest::second (24 bytes)   made not entrant
      

      这实际上意味着一个方法(这里是second)已经在tier level 3下编译,然后在层级4下它已经被进一步优化并且它已经被制作了3-d 层级不参加;这意味着它将被第 4 层的代码替换。

      【讨论】:

      • 你能告诉我这个解释的来源吗?
      • @merovingienne 这是我在阅读 jvm 源代码时记得的,我现在不记得确切的路径了...
      • @merovingienne 您可以在 Douglas Hawkins 的演讲中找到有关 Java JIT 的非常有用的信息:Understanding the Tricks Behind the JIT。他在 20:30 解释说“不得参加”。
      猜你喜欢
      • 2023-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多