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 это законно, просто неудобно.