Стратегия встраивания 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++;
}
}