Стратегия встраивания HotSpot JIT: сверху вниз или сверху вниз

Предположим, что у нас есть 3 метода: метод 2 вызывается из метода 1, метод 3 вызывается из метода 2. Методы 2 и 3 имеют размер 30 байтов каждый. Кроме того, предположим, что для определенности метод 2 всегда вызывается из метода 1 ровно один раз, а метод 3 всегда вызывается из метода 2 exaclty один раз.

Если метод 2 сначала вставлен в очередь, метод 3 будет вызываться непосредственно из тела метода 1 и может быть встроен в свою очередь. Если сначала метод 3 встроен в метод 2, размер последнего будет составлять около 60 байт-кодов, и он не может быть встроен, поскольку порог по умолчанию MaxInlineSize составляет 35 байт-кодов.

В каком порядке HotSpot JIT внедряет методы: сверху вниз или вниз?

Ответ 1

MaxInlineSize влияет на компиляции методов, выполняемых хотя бы один раз, но меньше, чем MinInliningThreshold раз. Для методов, выполненных более чем MinInliningThreshold, существует другой параметр -XX:FreqInlineSize=…, имеющий гораздо большее (зависящее от платформы) значение по умолчанию. Горячие точки все еще настроены независимо от MaxInlineSize. Вы можете протестировать его, запустив приложение с помощью -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining -XX:MaxInlineSize=0. Он по-прежнему будет сообщать о включении горячих точек (с комментарием "горячий" ). Только те методы, которые ранее сообщались как заключенные с комментарием "Выполненные < MinInliningThreshold times", могут затем получить комментарий к "слишком большому". Если вы установите FreqInlineSize, вы можете получить комментарии, такие как "горячий метод слишком большой". Я никогда не видел их с настройками по умолчанию.

Ответ 2

Выполнение приведенного ниже кода с параметрами показывает, что оба метода m3 сначала вложены. Я использовал следующие параметры для jvm: -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining. Очевидно, что метод, первый счетчик выполнения которого достигает порога вложения, сначала вложен. В нашем случае m3. Таким образом, для точки доступа, которую я использовал для тестирования, находится сверху вниз, когда m3 выполняется сначала, а выполнение m2 завершается.

Код запускался с jdk7_u40 при отключенном TieredCompilation, режиме сервера в окне 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 bytes, m2 есть 35 bytes и m3 имеет 31 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(m.i);
        System.out.println(m.j);
        System.out.println(m.k);
    }

    private void m1() {
        i++;
        m2();
        j++;
    }

    private void m2() {
        i++;
        i++;
        m3();
        j++;
    }

    private void m3() {
        i++;
        j++;
        k++;
    }
}