JVM - разница в содержании байт-кода после компиляции

Недавно я видел поведение, которое заставило меня спросить об этом на SO . Я надеялся, что люди тоже смогут поделиться своими выводами.

Будет ли файл класса (байт-код) отличаться, если один и тот же файл будет скомпилирован (без изменений) с использованием JDK 1.8 u66 и JDK 1.8 u121? Я имею в виду следующее:

1) Я компилирую приложение, используя JDK 1.8 u66. 2) Я вносю изменения в 1 или 2 файла и перекомпилирую, используя JDK 1.8 u66.

Могу ли я ожидать, что некоторые из неизмененных файлов классов будут иметь различное двоичное содержимое, даже если они не изменились?

Моя причина в том, что когда я взял хеш файла, который не был изменен как часть моих шагов выше - они имели одинаковый размер на диске, но хеш-код был совершенно другим. и я использовал Winmerge для сравнения этих двух версий, где размер был указан как идентичный, но двоичное содержимое было другим. Вот что я сравнил с помощью Winmerge (помеченный синим цветом элемент был связан с моим именем источника, поэтому мне пришлось его замаскировать), но, пожалуйста, обратите внимание на разницу в 208 и 248.

Это ожидается? если да, может кто-нибудь указать мне на эту литературу, которая объясняет это?

С Уважением,

1 ответ

Существует бесчисленное множество причин, по которым один и тот же исходный файл Java может быть скомпилирован в разные байты разными компиляторами, где разные версии одного и того же компилятора действительно должны рассматриваться как разные компиляторы. Даже для одного и того же компилятора нет гарантии, что байты идентичны.

Одна из таких причин заключается в том, что все ссылки в коде (кроме кодов операций и смещений байт-кода) перенаправляются через пул констант. Порядок записей в пуле констант не указан, и, следовательно, он может измениться, приводя ко всем ссылкам с использованием другого смещения.

Также обратите внимание, что в JVMS есть раздел под названием " Компиляция для виртуальной машины Java", который, однако, начинается со слов:

Нумерованные разделы в этой главе не являются нормативными

В результате рассуждение работает только в одном направлении: одни и те же байты подразумевают один и тот же исходный код, но разные байты не обязательно подразумевают разные исходные коды.

JDK-8067422, как связано с одним комментарием, приводит пример, когда даже один и тот же компилятор может создавать разные байты для одного и того же исходного файла (возможно, из-за разного набора исходных файлов, скомпилированных в одном и том же вызове компилятора). В соответствии с JLS и JVMS это законно, просто неудобно.

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