【问题标题】:JVM - bytecode content difference after compilingJVM - 编译后的字节码内容差异
【发布时间】:2018-04-19 18:08:01
【问题描述】:

我最近看到了一个让我在 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 的区别。

这是预期的吗?如果是这样,有人可以指点我解释这一点的文献吗?

问候,

【问题讨论】:

  • 您是否比较了字节码以发现它们的不同之处?
  • 是的,我做到了,它们在方法参数名称上有所不同,其中代码中的代码是 208 而不是 248。这是唯一的区别
  • 所以只有一个字节改变了?不过,我无法真正说出您所说的方法参数名称是什么意思。
  • @Bubleta 用截图更新了问题。
  • 这个问题可能是不稳定的lambda方法名造成的,见JDK-8067422

标签: java-8 jvm winmerge


【解决方案1】:

存在无数的原因,为什么同一个Java源文件可能被不同的编译器编译成不同的字节,其中同一个编译器的不同版本确实应该被视为不同的编译器。即使对于完全相同的编译器,也不能保证字节是相同的。

其中一个原因是,代码中的所有引用(操作码和字节码偏移量除外)都是通过Constant Pool 间接引用的。常量池中的条目顺序没有指定,因此它可能会改变,导致所有引用使用不同的偏移量。

另请参阅 JVMS 有一个标题为 Compiling for the Java Virtual Machine 的部分,然而,它的开头是:

本章编号部分不规范

因此,推理只在一个方向上起作用:相同的字节意味着相同的源代码,但不同的字节不一定意味着不同的源代码。

JDK-8067422,从一个评论链接,给出了一个例子,即使是同一个编译器也可以为同一个源文件产生不同的字节(可能是由于在同一个编译器调用中编译的不同的源文件集)。根据 JLS 和 JVMS,这是合法,只是不方便。

【讨论】:

猜你喜欢
  • 2012-08-11
  • 1970-01-01
  • 2014-03-05
  • 1970-01-01
  • 1970-01-01
  • 2020-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多