java PrintCompilation输出:“made not entrant”和“made zombie”的含义是什么?

运行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] 

我在我的博客上汇集了一些关于这方面的信息。 悬崖点击评论我发现说:

僵尸方法是通过类加载使代码无效的方法。 一般来说,服务器编译器会对非最终方法做出积极的内联决定。 只要内联方法从不被覆盖,代码是正确的。 当一个子类被加载并且该方法被覆盖时,编译后的代码将被打破以后的所有调用。 代码被声明为“不进入”(没有将来的呼叫者到破碎的代码),但有时现有的呼叫者可以继续使用代码。 在内联的情况下,这不够好; 现有的调用者的堆栈框架在从嵌套调用返回代码(或者只是在代码中运行)时会“去优化”。 当没有更多的堆栈框架将PC放入破碎的代码中时,它被声明为“僵尸” – 一旦GC开始移除,就可以将其移除。

这对我来说绝对不是一个专业领域,但是我对此感兴趣,所以做了一些挖掘工作。

您可能会感兴趣的几个链接: OpenJDK:nmethod.cpp , OpenJDK: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); } //... 

只是作为一个出发的地方。

这是一个在PrintCompilation上有着难以置信的大量信息的Gist 。 具体来说,它说:

当去优化发生时,如果决定使违规nmethod无效,则首先“不进入” 然后,当NMethodSweeper发现堆栈上再也没有激活时,它就是“制造僵尸”。