В этом посте рассматривается анализ побега, в частности, сколько времени требуется jvm для выполнения анализа побега в работающей программе. Я делаю некоторые замечания, но не имею всех объяснений на данный момент.
В качестве введения давайте немного посмотрим на малоизвестный и даже менее используемый флаг (который мы увидим хорошо) в jvm -Xcomp
.
Поведение для этого флага определено в документации jvm как:
-Xcomp
компиляция методов при первом вызове. По умолчанию клиентская виртуальная машина ( -client
) выполняет 1000 интерпретированных вызовов методов, а серверная виртуальная машина ( -server
) выполняет 10 000 интерпретированных вызовов методов для сбора информации для эффективной компиляции. Указание параметра -Xcomp
отключает интерпретированные вызовы методов для повышения производительности компиляции за счет эффективности.
На первый взгляд это кажется отличным вариантом. Быстрый путь к прогреву jvm через 10000 циклов — мы можем сразу же скомпилировать код. Разве мы не должны всегда включать эту опцию по умолчанию?
Но документация предупреждает, что это будет «за счет эффективности».
Jvm узнает о поведении кода в 10 000 циклов разминки, поэтому, когда дело доходит до компиляции, он компилируется наиболее эффективным способом. Компиляция кода сразу будет означать, что да, код действительно скомпилирован, но скомпилированный код может быть не самым эффективным. Вы можете прочитать больше об этом в этом посте — но это не совсем тема этого поста.
Что-то еще, что не произойдет, если вы используете -Xcomp, это escape-анализ. Это на самом деле довольно удивительно, поскольку jvm не нужно узнавать о том, возможен ли escape-анализ при запуске программы. Это должно быть видно по статическому анализу кода.
Взгляните на этот код (я был вдохновлен идеями в этом блоге):
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
import java.io.IOException; import java.util.Optional; /** * Created by daniel on 17/12/2015. */ public class Test { private static String NAME; public static void main(String[] args) throws IOException { new Test().test(); } public void test() throws IOException { Name name = new Name( "Steven" ); int iterations = 1_000_000; for (;;){ countOptional(name, iterations); System.out.println( "Press any key to continue" ); System.in.read(); } } private static void countOptional(Name name, int iterations) { for ( int i = 0 ; i < iterations; i++) { NAME = name.getOptionalName().get(); } System.out.println(iterations + " optional iterations " + NAME); } class Name { private final String name; public Name(String name) { this .name = name; } public Optional<String> getOptionalName() { return Optional.ofNullable(name); } } } |
Нам нужно убедиться, что программа работает без gc (я предлагаю следующие флаги):
1
|
-verbosegc -Xmx4g -Xms4g |
Когда программа ожидает ввода, выполните дамп кучи, чтобы увидеть, сколько Optional
объектов было создано. Затем нажмите любую клавишу, чтобы возобновить программу.
Чтобы выполнить дамп кучи, сначала запустите jps
чтобы определить pid программы, а затем выполните:
1
|
jmap -histo pid | head |
Сделайте это один раз без флага -Xcomp и один раз с флагом -Xcomp.
Без флага -Xcomp
После первой итерации:
После второй итерации:
Все последующие итерации одинаковы, дополнительные объекты не создаются:
После 234 тыс. Итераций явно проскакивает анализ — не уверен, почему это займет так много времени, обычно (например, при компиляции кода) 10 тыс. Итераций достаточно? Также во второй итерации он создает еще ~ 400 тыс. Объектов, прежде чем удастся выполнить анализ, что также немного загадочно.
С флагом -Xcomp
После первой итерации:
После второй итерации:
После каждой итерации число Optional
объектов увеличивается на 1 метр.
Резюме
- -Xcomp — это переключатель, который почти наверняка никогда не следует использовать в производстве. Я могу представить некоторые сценарии, в которых вы можете поиграть с отключением интерпретатора, но это будут очень специфические крайние случаи.
- Похоже, для эффективности анализа побега требуется не менее 200К итераций. Таким образом, для полного прогрева вам нужно больше 10 000 итераций.
- Существует также другая фаза, когда после выхода из объекта, кажется, нужно сделать это снова. Это требует дальнейшего понимания.
- Если вы немного замедлите программу, выполнив некоторую работу между вызовами для создания Optional, число объектов уменьшится. Например, я обнаружил, что вызов Math.sin уменьшает число необязательных объектов примерно на 50%.
Ссылка: | Сколько времени требуется JVM для анализа побега? Может быть, дольше, чем вы думаете. от нашего партнера JCG Даниэля Шая из блога Rational Java . |