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.

введите здесь описание изображения

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

С уважением,


person ha9u63ar    schedule 18.04.2018    source источник
comment
Вы сравнивали байт-код, чтобы найти, где они отличаются?   -  person Bubletan    schedule 19.04.2018
comment
да, они различались по имени параметра метода, где код говорил 208 вместо 248 в коде. Это единственная разница   -  person ha9u63ar    schedule 19.04.2018
comment
То есть изменился только один байт? Я не могу точно сказать, что вы подразумеваете под именем параметра метода.   -  person Bubletan    schedule 19.04.2018
comment
@Bubleta Обновил вопрос со скриншотом.   -  person ha9u63ar    schedule 19.04.2018
comment
Проблема может быть вызвана нестабильными именами лямбда-методов, см. JDK-8067422.   -  person apangin    schedule 19.04.2018


Ответы (1)


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

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

См. также, что в JVMS есть раздел под названием Компиляция для Java Virtual Machine, которая, однако, начинается со слов:

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

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

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

person Stephan Herrmann    schedule 19.04.2018
comment
@StephanHermann Спасибо. Однако я бы склонился к jira JDK, потому что там ясно сказано, что проблема исправлена ​​для JDK9. Так что пока это JDK8, у меня будут проблемы. - person ha9u63ar; 19.04.2018
comment
@ ha9u63ar ha9u63ar, возможно, вы правы, но моя точка зрения такова: даже после устранения проблемы нет гарантии для одинаковых байтовых кодов. - person Stephan Herrmann; 19.04.2018
comment
@StephenHerrmann Я понимаю это. Но все же неправильно ли говорить, что до тех пор, пока JDK идентичен, и если я компилирую один и тот же класс 5 раз подряд без изменения каких-либо байтов, они должны быть идентичными при условии, что лямбда-выражения отсутствуют? или даже это неправильно? - person ha9u63ar; 19.04.2018
comment
@ ha9u63ar ha9u63ar для этого нет требований в спецификации компилятора, как указал Стефан, цитируя JVMS. - person Nándor Előd Fekete; 19.04.2018