GraalVM — Byte Code to Bit Code

Pratik Prakash
The Startup
Published in
7 min readSep 11, 2020

GraalVM & Micronauts — frenzy way to MicroServices, Serverless: Part1

Photo by Alexander Sinn on Unsplash

Early adopters for Cloud-Native ( microservices, serverless ) are now moving to its next wave called v2.x. leveraging the maturity, learnings, and identified shortfalls to design next-level stuff.

Let’s recap few purposes of going cloud-native that we will relate here:

  • Scalability
  • Cost — Memory vs Runtime
  • Start-up & execution time ( cold start in Serverless )
  • Throughput
  • Enable polyglot

The current era of microservices is dominated by Java + other JVM based languages by large. Beside JVM’s super-rich ecosystem of libraries, frameworks, community support etc. few observation like thick memory footprint, cold startup & extended execution time, less polyglot support factored engineers for moving away from JVM platforms towards non-JVM stuff like nodeJs, Go-Lang, Python for cloud-native ecosystem.

GraalVM — An Oracle Labs initiative in collaboration with open source community supported by (VMWare, Red Hat, Microsoft, Twitter, Amazon and more.). To quote from their website :

It is a new universal virtual machine that supports a polyglot runtime environment and the ability to compile Java applications down to native machine code. GraalVM removes the isolation between programming languages and enables interoperability in a shared runtime.

Oracle Labs White Paper
@copyright Pratik Prakash

Why the community is enthusiastic about GraalVM?

“GraalVM — Byte code to Bit Code” 😀😀

  1. GraalVM — Accelerating Application Performance :
    GraalVM a modern JVM build on Oracle Java SE can improve the performance of any application written in Java or JVM without any single line change in existing code. It reduces the response time of end-user that in turn free up CPU, memory consumption and can be better utilized for more capacity and load handling.
  2. GraalVM — Highly Optimized Compiler
    The GraalVM compiler is highly optimized to enhance the pre-written application or the new one with its 62 separate compiler optimization algorithms (called “Phases”), of which 27 are patented. Many JVM languages (e.g., Java, Scala, Kotlin) will see around a 30%–40% speedup using GraalVM when compared with Java SE-8.
GraalVM Enterprise Renaissance Benchmark Performance — Oracle White Paper

3. GraalVM — “Native imaging”
GraalVM “Native imaging” allows ahead of time compilation of Java code to a standalone executable called “native image”. It includes the application classes, classes from its dependencies, runtime library, classes from JDK and statically linked native code from JDK by using AoT (ahead-of-time compiler) for a specific operating system and architecture directly. It does not run on the Java VM, but includes necessary components like memory management and thread scheduling from a different virtual machine called “Substrate VM”.

GraalVM Native image supports JVM-based languages, e.g. Java, Scala, Kotlin etc.GraalVM native binary executables have incredibly fast load and execution time(since program initialisation can be done at build time and the application is already compiled) and much smaller footprint (since the JVM and JIT compiler don’t have to be distributed).

This is especially important during a cold start (e.g. serverless on demand start-up) as there is really no time to waste waiting for Spring Boot, JRE to configure itself. In this case, the system would already face a considerable backlog of events to process.
In case of GraalVM, it needs to know in advance which bytecode is going to be executed. Features like runtime dependency injection (on which Spring Boot relies heavily) will not work out of the box. Instead, a framework like
Micronaut (which uses compile time dependency injection, proxy objects etc.) can be leveraged. In addition, the time it takes to create a native image is quite considerable. A typical compilation to a native image might take several minutes, so this step is one you would like to do e.g. during a nightly build.

export GRAALVM_HOME=
export PATH=$GRAALVM_HOME/bin:$PATH
# gu is the Graal Updater, it is used for installing additional packages,in this case the package for building native images
gu install native-image
# mn- Micronauts framework to leverage Native-Image
native-image --no-server -cp target/demo-mn-0.1.jar

One can build a native image directly with Maven using the mvn packagecommand without running the native-image plugin.

<plugin>
<groupId>org.graalvm.nativeimage</groupId>
<artifactId>native-image-maven-plugin</artifactId>
<version>${graalvm.version}</version>
<executions>
<execution>
<goals>
<goal>native-image</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<skip>false</skip>
<imageName>example</imageName>
<buildArgs>
--no-fallback
</buildArgs>
</configuration>
</plugin>

4. Substrate VM — a subproject within Graal (VM)
“Native-Image” code does not run on Java VM, but includes necessary components like memory management and thread scheduling from a different virtual machine, called “Substrate VM”. It is a native runtime component (like the deoptimizer, garbage collector, thread scheduling etc.). The resulting program has faster startup time and lowers runtime memory overhead compared to a Java VM.

Ref: Oracle White Paper

5. GraalVM’s — ( Ahead of Time Compiler) AoT vs OpenJDK’s JIT
This just-in-time compilation understands the workload over time and optimize the final code depending on its nature. That’s the reason why over time the JVM is considered more performant than native executables doing the same.
Features like reflection and proxies, heavily used by dependency injection centered frameworks such as Spring, pose a serious challenge for AoT compilation.

Hotspot JVM JIT is like a Diesel engine vs Petrol engine (AoT)

Those relationships require to be manually declared in configuration to allow the compiler know about them — you guessed it — ahead of time.
Recently, two new JVM frameworks based onGraalVM with this approach in mind:
Micronaut and Quarkus.

6. GraalVM — MicroService & Serverless — for CloudNaitve EcoSystem
Microservices and serverless architectures are being implemented or are part of the roadmap in most modern solution stacks. Given that Java is still the dominant language for business applications, the need for reducing the startup time for Java is becoming more important. Serverless architectures are one such area that needs faster startup time along with applications hosted on the container platform.
Several projects have accepted GraalVM Native Image as a platform for their applications like Quarkus, Micronaut. Spring Framework recently announced the upcoming support for native images.

7. GraalVM — Execution and Start-up time
“Loading Time Affects Your Bottom Line”
GraalVM allows you to compile a program ahead of time into a native executable that runs with Substrate VM. Substrate VM is written in Java and compiled into the native executable. The resulting program has faster startup time and less runtime memory overhead compared to a Java VM.

We measured the startup and memory footprint of a basic microservice build in Micronaut.

My GitHub Repo for Demo Apps build with Micronauts for benchmarking :
https://github.com/scanpratik/micronauts-GraalVM--JIT
https://github.com/scanpratik/micronauts-nativeImage-GraalVM
https://github.com/scanpratik/graalVM-SpringBoot2.X

Ref: https://www.graalvm.org
Ref: https://www.graalvm.org

8. GraalVM Polyglot Runtime
“Truffle Language Implementation Framework”
A new language implementation framework called Truffle makes it possible to implement language interpreters that are both simple and high performance. So GraalVM is not only a JIT compiler and ahead-of-time native compiler for Java, but it can also be a JIT compiler for JavaScript, Ruby, R, and Python. Polyglot embeddings can also be compiled ahead-of-time.

Ref: Oracle White Paper of GraalVM

Your pom.xml file as for using Truffle plugin :

<dependency>
<groupId>org.graalvm.truffle</groupId>
<artifactId>truffle-api</artifactId>
<version>20.1.0</version> <!-- or any later version -->
</dependency>
<dependency>
<groupId>org.graalvm.truffle</groupId>
<artifactId>truffle-dsl-processor</artifactId>
<version>20.1.0</version>
<scope>provided</scope>
</dependency>
$ gu install native-image
$ gu install ruby
$ gu install python
$ gu install R

Cloud-Native Microservices, Serverless — Design Decision :
Sometimes good performance means good throughput, sometimes it means low memory usage, and sometimes it means a fast cold-start startup time.

GraalVM vs Hotspot VM ( OpenJDK) — A Trade-offs while selecting Native Image:
Benefits of “Native-image” aren’t for free — they come with a cost.
Obviously the native executable can only run on a single platform. Another limitation is caused by missing metadata during runtime. Since by default native image doesn’t retain information about classes and methods, hence one’s ability to perform reflection is limited. As there are many Java frameworks that rely on reflective access, getting them run on Native Image may require additional configuration.

Let’s see in next section, Part2 — how next wave of Microservices and Serverless are getting build based on modern frameworks like Micronaut build on GraalVM.

--

--