java 8 中的编译代码与 java 11 中的编译代码

Compiled code in java 8 vs Compiled code in java 11

我们目前在 Java 8 中编译了代码,但我们在 Java 11 VM 上 运行。 现在我们正尝试将我们的代码也移动到 Java 11 编译时间。想知道 Java 8 中的编译代码与 Java 11 中的编译代码在性能方面是否有任何好处,因为两个编译器将生成不同的 class 文件(字节码)?两者在效率方面有何不同?

javacnot an optimizing compiler,所以一般来说,不要指望它在不同版本之间产生“更快”的字节码。优化是 JVM 的工作。

同时,Java编译器确实支持新的语言特性,可能支持新的 JVM 特性。其中一些确实对性能有影响。 JDK 9 - JDK 11 中最著名的示例如下。

  1. JEP 280: Indify String Concatenation (JDK 9).

    这个 JEP 改变了字符串连接表达式的编译方式。在JDK 9之前,字符串+表达式被翻译成

    new StringBuilder().append()...append().toString();
    

    尽管 JIT 识别此类链并尝试在运行时优化它们,但这种优化很脆弱并且并不总是按预期工作。使用 invokedynamic 编译字符串连接使 JVM 可以更自由地生成更好的代码。您可以在这个 JEP 的 notes 中找到详细的解释和基准。

  2. JEP 181: Nest-Based Access Control (JDK 11)

    这个 JEP 解决了访问嵌套 类 的私有成员的问题。在 JDK 11 之前,Java 编译器为它们生成了合成桥方法 (example)。

    乍一看,这与性能无关。但是,在 marginal cases 中,由于内联深度限制,额外的合成方法可能会破坏内联。

    Nest-Based 访问控制允许 nestmate 类 无需合成桥即可访问彼此的私有成员,从而降低意外性能下降的风险。

更新

之前我将 JDK-8175883: Bytecode Generation for Enhanced for Loop 包含在此列表中,但正如@Holger 在评论中注意到的那样,这种“优化”实际上并没有起作用。

结论

Java 编译器中的更改主要与新的 language/JVM 功能有关。字节码级优化不是目标。但是,其中一些更改也可能(间接)影响性能。无论如何,重新编译代码可能带来的性能优势通常很小,您甚至不会在实际应用程序中注意到它们。