1

The project I work on is data-heavy, and performance matters.

It is currently being compiled from Kotlin with -target 11, but somewhere, it runs on JRE 17+.

Would it make a difference in performance if it was compiled with target 17? As far as I have seen, there were not many bytecode changes between 11 and 17. Are there any theoretical articles or benchmarks?

(Hypothetically, I could measure myself, but due to how the project is built and deployed, moving everything to Java 17 would be quite a lot of effort just to try -target 17. The upgrade is scheduled for later.)

Here is a very old similar question for -source 1.4 and -target 1.7: Using -target higher than -source with javac

Ondra Žižka
  • 43,948
  • 41
  • 217
  • 277

1 Answers1

4

Here is a list of improvements you may get automatically when compiling (unchanged) Java source code targeting a newer Java version, ordered by their minimum target version:

  • JDK 1.4: Early initialization of outer this reference.
    Starting with this version, the synthetic field holding the reference to the outer instance is initialized before calling the super constructor. This is a stability/robustness improvement, not affecting the performance

  • JDK 1.5/Java 5: String concatenation without synchronization
    Prior to this version, string concatenation used StringBuffer under the hood, which performs unnecessary synchronization. Starting with this version, string concatenation gets compiled to code using StringBuilder which does not perform synchronization.

  • JDK 1.5/Java 5: Direct support for class literals in bytecode
    Class literals like Foo.class get compiled to a single bytecode instruction. Prior to this version, it was syntactic sugar for calling Class.forName("Foo") and remembering the result in a synthetic static field. The direct support requires less code and may be slightly faster.

  • Java 6: StackMapTables to improve verification speed.
    This version introduced StackMapTables (for the ordinary desktop/server JVMs) which provide hints to the verifier. This can reduce startup time.

  • Java 9: String concatenation using invokedynamic.
    Starting with this version, string concatenation gets compiled to a single invokedynamic instruction instead of a sequence of append calls on a StringBuilder. This can reduce the bytecode size dramatically. Further, this opens the opportunity to the runtime, to provide faster implementation code. Note that currently this applies to javac only, not to Eclipse’s ecj.

  • Java 11: Nest based access
    This features allows classes belonging to a nest (typically inner classes/nested classes) to access each others private members directly, without additional helper methods. This will reduce the code size and may in some cases improve performance, e.g. when a long call chain exceeded inlining limits and does not anymore.

  • Java 18: No unnecessary outer references in inner classes.
    Prior to this version, inner classes always had a synthetic field referencing the outer instance. Starting with this version, the field is only maintained if the inner class actually accesses the outer instance. This may have a positive impact on garbage collection performance (and slightly reduce code size).

So the general answer is that recompiling source code targeting a newer version can have a benefit, but specifically switching from 11 to 17 has not, to my knowledge.

Also, these improvements apply to the standard Java compiler and will affect Kotlin only when its compiler also adopts the changes. On the other hand, the Kotlin compiler could also use JVM/Bytecode/Platform enhancements which the Java compiler doesn’t use.

Holger
  • 285,553
  • 42
  • 434
  • 765