Анализ побега сомнений
Я решил провести небольшой эксперимент с анализом 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.