Native image with GraalVM

Ahead-of-time compilation, tuned for performance


GraalVM

High-performance JDK distribution designed to accelerate the execution of applications written in Java and other JVM languages while also providing runtimes for other popular languages.

GraalVM = HotSpot JVM 
          + Graal JIT compiler
          + ability to run other languages (JS, Python, ...)
          + AOT compiler
          + additional bundled tools
          + ...

GraalVM

graalvm


AOT: native image

AOT compiled Java code to a standalone native platform executable.


AOT: native image build process


AOT: native image build process

Graal compiles ALL the reachable code into a platform specific native executable that is fully functional on its own and doesn’t need a JVM to run.


AOT: runtime

Who takes care of runtime features like memory management and thread scheduling?

SubstractVM

Slim VM implementation that provides runtime components.


AOT vs JIT: startup

aot vs jit startup


AOT vs JIT: startup

JIT

  • load JVM executables
  • load classes from the file system
  • verify bytecodes
  • start interpreting
  • run static initializers
  • first-tier compilation
  • gather profiling feedback
  • second tier compilation(C2 or GraalVM)
  • finally, run with the best machine code

AOT vs JIT: startup

AOT

  • load executable with a prepared heap
  • immediately start with the best machine code

AOT vs JIT: startup

aot vs jit startup

https://medium.com/graalvm/lightweight-cloud-native-java-applications-35d56bc45673


AOT vs JIT: memory footprint

aot vs jit memory footprint

https://medium.com/graalvm/lightweight-cloud-native-java-applications-35d56bc45673


Game changer for serverless architecture

Java can stands on the same level as other programming languages in the serverless world!


Demo

converter-worker


AOT vs JIT: trade-offs


AOT vs JIT: trade-offs

aot vs jit performance


AOT: pain points

Met 18 issues when building the converter-worker in native image…


AOT: pain points - builds

  • CPU hungry
  • memory hungry
  • long build
    • native build time: ~3m38s
    • traditional build time: ~15s

compiling


AOT: pain point - no immediate feedback

When developing in local, we are usually working in traditional mode.


AOT: pain point - 3rd party libraries

Not every libraries can support native mode.


AOT: pain point - OkHttp

GraalVM / Quarkus are using an old version of okhttp conflict with annotations-client auto-generated SDK.

Implemented an annotations-client using native Java HttpClient


AOT: pain point - logger

Some loggers like slf4j uses static singleton and the classpath to know which log implementation it should use (logback, log4j2, …).

Native build needs to access to ALL reachable codes, so the build fails need to add substitutes:

@TargetClass(io.netty.util.internal.logging.InternalLoggerFactory.class)
final class Target_io_netty_util_internal_logging_InternalLoggerFactory {
 
    @Substitute
    private static InternalLoggerFactory newDefaultFactory(String name) {
        return Slf4JLoggerFactory.INSTANCE;
    }
}

AOT pain point - new Java features

The release train is as follows:

Java -> framework / libraries -> Graal / native

E.g. Java 17 support only available on May 2022! Java 17 LTS was released on 2022-09-14 8 months!


AOT pain point - reflection

By design, reflection is not supported.

Need to declare all the classes that are instanciated using reflection in a JSON file (including the serde with Jackson):

[
  {
  "name": "com.bioserenity.converter.domain.model.Job",
    "allDeclaredConstructors": true,
    "allPublicConstructors" : true,
    "allDeclaredMethods" : true,
    "allPublicMethods" : true,
    "allDeclaredFields" : true,
    "allPublicFields" : true
  },
  {...}
]

Use libraries as little as possible!


Resources