Анализ побега сомнений

Я решил провести небольшой эксперимент с анализом escape (Java 8, 64-битная серверная JVM). Я придумал это действительно глупое "приложение", в котором я создаю множество объектов Address (они состоят из почтового индекса, улицы, страны и отметки времени, в течение которого был сгенерирован объект. Кроме того, в Address есть метод isOk(), который возвращает истина, если отметка времени делится на 7...).

Итак, вот программа:

private boolean generate() {
    boolean valid = true;
    for (int i=0;i<1_000_000_000;i++) {
        valid = valid && doGenerate();
    }

    return valid;
}

private boolean doGenerate() {
    long timeGenerated = System.currentTimeMillis();
    Address address = new Address(1021, "A Street", "A country", timeGenerated);
    return address.isOk();
}

Пока все хорошо, я профилировал его с помощью jVisualVM, в куче нет объектов Address, пока он работает. Все приложение завершается за несколько секунд.

Тем не менее, когда я рефакторинг это так:

private boolean generate() {
    boolean valid = true;
    for (int i=0;i<1_000_000_000;i++) {
        long timeGenerated = System.currentTimeMillis();
        Address address = new Address(1021, "A Street", "A country", timeGenerated);
        valid = valid && address.isOk();
    }

    return valid;
}

Бааанг, нет escape-анализа, каждый объект Address в конечном итоге размещается в куче с большими циклами сборки мусора. Почему это так? Я имею в виду, что экземпляры Address не выходят в любом случае (во второй версии область действия объектов Address еще более узкая, они не выходят за пределы метода, даже блока for), так почему две версии ведут себя так по-разному?

1 ответ

Решение

Вы пишете " который возвращает истину, если отметка времени делится на 7 ". Это должно сделать очевидным, что происходит. В вашем первом коде:

boolean valid = true;
for (int i=0;i<1_000_000_000;i++) {
    valid = valid && doGenerate();
}
return valid;

valid станет false как только отметка времени не делится на 7, Затем, согласно способу && работает, так и останется false навсегда и с тех пор && является коротким замыканием, метод doGenerate(), который несет распределение, никогда не будет вызван снова.

Напротив, в вашем втором варианте

boolean valid = true;
for (int i=0;i<1_000_000_000;i++) {
    long timeGenerated = System.currentTimeMillis();
    Address address = new Address(1021, "A Street", "A country", timeGenerated);
    valid = valid && address.isOk();
}
return valid;

valid также станет и останется false как только отметка времени не делится на 7, но единственное, что закорочено, это вызов isOk(), Строительство происходит независимо от стоимости valid,

В принципе, строительство Address может быть устранено здесь, но для этого потребуется замена в стеке, как это должно происходить во время работы вашего цикла. Неясно, является ли это проблемой здесь, но более важный вывод заключается в том, что ни в одном из случаев мы не видим, как происходит EA, как в первом случае, вы не вызываете метод, содержащий распределение (после неизвестного, но ожидаемого небольшого числа заклинаний) вообще.

Таким образом, два примера не эквивалентны и не позволяют сделать выводы об Escape Analysis.

Другие вопросы по тегам