HotSpot JIT内联策略:自上而下或下至上

假设我们有3个方法:从方法1调用方法2,从方法2调用方法3.方法2和3各自大小为30个字节码。 另外,假设确定性方法2总是从方法1中恰好调用一次,并且方法3总是从方法2中调用一次。

如果方法2首先被内联,则方法3将直接从方法1的主体调用,并且可以依次内联。 如果方法3首先内联到方法2中,则后者的大小将变为大约60个字节码,并且不能内联,因为默认的MaxInlineSize阈值是35个字节码。

HotSpot JIT以哪种顺序内联方法:自上而下或下至上?

MaxInlineSize影响至少执行一次但小于MinInliningThreshold次数的方法的编译。 对于执行超过MinInliningThreshold方法,有一个不同的设置-XX:FreqInlineSize=…具有更大(平台相关)的默认值。 无论MaxInlineSize如何,热点仍然是内联的。 您可以通过使用-XX:+UnlockDiagnosticVMOptions运行应用程序来测试它-XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining -XX:MaxInlineSize=0 。 它仍将报告热点的内联(这些与评论“(热)”)。 只有以前报告为注释“执行FreqInlineSize您可能会收到“hot method too big”之类的评论。 我从未在默认设置下看到它们。

使用参数运行以下代码可以发现两个方法m3都是先内联的。 我对jvm使用了以下参数: -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining 。 首先,内联首先执行计数达到内联阈值的方法。 在我们的情况下m3。 因此,我用于测试的热点是首先执行m3并且m2执行结束。

使用jdk7_u40运行代码,禁用TieredCompilation,Windows 8框上的服务器模式。 该命令的输出是:

  @ 66 java.lang.String::indexOfSupplementary (71 bytes) too big @ 21 methodTest::m3 (31 bytes) inline (hot) @ 11 methodTest::m2 (35 bytes) inline (hot) @ 21 methodTest::m3 (31 bytes) inline (hot) @ 14 methodTest::m1 (25 bytes) inline (hot) @ 11 methodTest::m2 (35 bytes) inline (hot) @ 21 methodTest::m3 (31 bytes) inline (hot) 

m1大小为25 bytesm235 bytesm331 bytes

 public class methodTest { public static void main(String[] args) { doTest(); } int i = 0; int j = 0; int k = 0; private static void doTest() { methodTest m = new methodTest(); for (int i = 0; i < 1000000000; i++) { m.m1(); } System.out.println(mi); System.out.println(mj); System.out.println(mk); } private void m1() { i++; m2(); j++; } private void m2() { i++; i++; m3(); j++; } private void m3() { i++; j++; k++; } }