javac是否根据底层操作系统进行任何字节码级别的优化?

3
我理解的是,通过调用javac生成的Java字节码与底层操作系统无关,但是HotSpot编译器将根据程序运行情况执行特定于平台的JIT优化和编译。然而,我在32位JDK上编译了代码,并在32位JVM下的Solaris上执行(两个操作系统都不是64位)。据我所知,Solaris x86盒子在所有方面都应该优于Windows盒子(核心数量、内存量、硬盘延迟、处理器速度等等)。然而,同样的代码在Windows上运行比在Solaris上更快(单个数据点是在Windows上花费7.5秒,在Solaris上花费超过10秒),这种情况一直存在。我的下一个测试是在Solaris上进行编译并注意性能差异,但是这对我来说毫无意义,并且我找不到任何Oracle文档来解释我所看到的现象。
如果在两个不同的操作系统上使用相同版本(主要、次要、发布等)的JVM,在相同的源文件上调用javac,是否会在Java字节码(生成的.class文件)中产生不同的优化?有没有任何解释这种行为的文档?

我会说你的Windows虚拟机被更好地优化了。不过在Solaris上编译代码并比较javac输出结果。 - Paŭlo Ebermann
6个回答

3
不,javac在不同平台上不会进行任何优化。
请参见Oracle的“工具”页面(其中描述了javac和其他工具):
每个开发工具都有一个Microsoft Windows版本(Windows)和一个Solaris或Linux版本。 版本之间的特性几乎没有区别。 但是,为了满足每个操作系统的特殊要求,配置和使用方面存在一些小差异。(例如,您指定目录分隔符的方式取决于操作系统。)
(也许Solaris JVM比Windows JVM慢?)

我遇到过这个问题,但是“features”意味着能力,而不一定是如何执行这些能力。仅仅因为我可以编译并不意味着编译过程是相同的。在会议之前,我需要计算一些性能数据,所以我不能在那之前重新构建和运行测试。最好回答我的问题的是(看起来并不存在)一个正式的规范,它说javac在Oracle javac工具的所有实现中表现完全相同,无论操作系统如何。 - Thomas Owens
2
@Thomas Owens 这是常识。已经持续了十五年甚至更久的时间。你不需要测试用例,只需要比较一些二进制文件就可以证明它。 - user207421
1
@Thomas Owens,这来自我在Java方面14年的经验。二进制比较也是一个“相当简单的想法”,并且它也是“科学有效”的。特别是如果您比较编译器二进制文件。您似乎固执于创造不必要的工作。 - user207421
1
@Thomas,你不会找到文档说编译器是线程安全的,在午夜工作或者面向麦加时才能工作。怀疑这是个问题毫无意义,所以为什么要记录每一个人们可能担心的事情呢? - Peter Lawrey
2
@Thomas:实际的编译器二进制文件是tools.jar,而不是启动虚拟机的可执行文件。 - Paŭlo Ebermann
显示剩余6条评论

1
编译输出不应该依赖于调用 javac 的操作系统。 如果您想验证它,请尝试:
me@windows@ javac Main.java
me@windows@ javap Main.class > Main.win.txt

me@linux@ javac Main.java
me@linux@ javap Main.class > Main.lin.txt

diff Main.win.txt Main.lin.txt

看起来手动验证是唯一的选择。我可能可以自动化它,因为我将要验证数百个.class文件是否相同,但到目前为止,没有人能够提供Oracle品牌的文档。 - Thomas Owens

1

不过我还是决定去谷歌一下。 ;)

http://java.sun.com/docs/white/platform/javaplatform.doc1.html

Java平台是一种新的软件平台,用于在网络计算机系统上交付和运行高度交互式、动态和安全的小应用程序和应用程序。但是Java平台的独特之处在于它位于其他平台之上,并执行字节码,这些字节码不特定于任何物理机器,而是虚拟机器的机器指令。使用Java语言编写的程序编译为一个字节码文件,可以在Java平台存在的任何基础操作系统上运行。换句话说,同一个文件可以在运行Java平台的任何操作系统上运行。这种可移植性是可能的,因为Java平台的核心是Java虚拟机。


一个常见的错误,特别是如果你开发C/C++,就是假设编译器会优化代码。它只进行一种优化,即评估编译时已知的常量。

当然,编译器远不如你想象的那么强大,因为它只验证代码并生成尽可能与你的代码匹配的字节码。

这是因为字节码是为理想化的虚拟机而设计的,在理论上不需要任何优化。希望当你以这种方式思考时,编译器不做太多事情就有意义了,因为它不知道代码实际上将如何使用。

相反,所有的优化都是由JVM中的JIT执行的。这完全取决于平台,并且可以生成32位或64位代码,并使用运行代码的处理器的确切指令。它还将根据实际使用情况优化代码,这是静态编译器无法做到的。这意味着代码可以基于不同的使用模式重新编译多次。;)


0

延伸dacwe的观点,“也许Solaris JVM比Windows JVM慢?”

有一些配置选项(例如,是否使用客户端或服务器vm [链接], 还可能有其他选项),其默认值取决于操作系统。因此,这可能是Solaris VM在这里较慢的原因。


0
据我了解,javac 只考虑 -target 参数来决定生成哪种字节码,因此在字节码生成中没有特定于平台的内容。
当解释字节码时,所有优化都是由 JVM 而不是编译器完成的。这是特定于各个平台的。
另外,我在某处读到过 Solaris JVM 是参考实现,然后被移植到 Windows 上。因此,Windows 版本比 Solaris 版本更加优化。

这也是我的理解,但我还没有找到任何明确说明的文档。如果有这样的资料,会节省我很多时间。 - Thomas Owens
@Thomas,这是“编译一次,到处运行”的口号的一部分。如果不同的操作系统甚至只有一个字节的字节码结果不同,那就是一个错误。您应该能够比较实际的字节码以查看差异或检查所有类的校验和(如果将它们放在一个jar文件中)。 - Peter Lawrey
@Thomas,你可以查看OpenJDK项目中的编译器源代码来确定。Eclipse编译器也是开源的,可以替代javac。 - Thorbjørn Ravn Andersen

0
javac是否根据底层操作系统执行任何字节码级别的优化?
不会。
确定为什么程序在两个平台上的性能特征不同需要在相同的工作负载下对它们进行分析,并仔细分析方法执行时间和内存分配/垃圾回收行为。你的程序是否执行任何I/O操作?

我现在正在进行性能分析。这里涉及到文件读取、数据库连接以及将日志记录到文件和控制台。测试用例中的数据集是相同的,并且在两种情况下都是本地读取,这就是为什么我感到惊讶的原因,因为一个“更强大”的服务器(或者我被告知是这样 - 我仍然没有确切的规格)在性能方面表现不佳。 - Thomas Owens
I/O让情况复杂了很多。你的数据库都调优了吗? - Amir Afghani
我不管理数据库端。那是其他人的事情。我只是试图证明它不是软件导致了显著的减速。根据我的数据,总体花费时间的比率似乎是一致的,因此看起来所有的问题都归结于调整JVM和数据库以尝试挤取更多的性能。 - Thomas Owens

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接