What is a GraalVM

GraalVM, also developed by Oracle, is a cross-language full-stack VIRTUAL machine enhanced on HotSpot. A full-stack virtual machine is a platform that can run most languages (including Java, Scala, Groovy, Kotlin, JavaScript, Ruby, Python, C, C++, etc.). It is also possible to compile mixed-language programs (mixing interfaces or methods from different languages, etc.). In the case of Java, since it is developed based on HotSpot, it is naturally capable of being used as a full Java standard compliant virtual machine. The difference is only in the just-in-time compiler: the C2 embedded in HotSpot has been replaced with Graal.

Graal compiler

At the heart of GraalVM is the Graal compiler, an excellent JIT compiler. It can be used either as a JIT compiler or as a pre-compiled static compiler.

Graal is also written in the Java language (JVMCI), supports common compiler optimizations, and supports more complex optimizations (partial escape analysis, aggressive predictive optimizations, etc.). Since JDK10, HotSpot has also introduced Graal. Primarily intended as a replacement for C2, it takes advantage of its strengths, eliminates its weaknesses, and is more maintainable and extensible than C2 (which has become so complex that even the original author, Cliff, was reluctant to maintain it). Graal, however, is still in the experimental stage and is disabled by default, requiring a parameter to activate.

Truffle

Truffle is another key component of GraalVM, a programming language implementation framework that provides a set of apis that can be used to implement an AST interpreter for a language and can be optimized by the Graal compiler. Most language interpreters are already implemented by Oracle, as you can see from the figure above: JS, Ruby, R, Python, Sulong (Sulong is an interpreter for LLVM IR). There are also many people who have implemented interpreters for other languages and put them on Github.

The beauty of Truffle is that all languages use a common protocol to develop their interpreters, which means that all interpreters at runtime can use a common protocol to manipulate objects in different programming languages. All code that is not written in language, or written in a mixture of languages, is the same at run time. Programs written in different languages or multiple languages can be optimized just like normal code, without any additional overhead.

This means that when you develop in Java, Python has a great library that Java doesn’t have. Instead of using Java to implement the Pyhton library again, you can simply call the Python library from Java code.

Another benefit is that because the runtime looks like all languages are the same, this means that tools can also be multilingual, such as using VisualVM to analyze JavaScript memory usage

Substrate VM

SubstrateVM is an AHEAD-of-time (AOT) compilation framework Of GraalVM. AOT is ahead of time compilation. Unlike just-in-time compilation (JIT), AOT converts bytecode into machine code before the program is run, which can be compiled directly into standalone executable files (local images) or shared libraries.

SubstrateVM is designed to provide a Java runtime with high startup performance, low memory overhead, and seamless integration of C code. SubtrateVM is completely separate from the HotSpot VIRTUAL machine and has a separate runtime with components such as exception handling, synchronization, thread management, memory management (garbage collection) and JNI.

SubstrateVM can be divided into two parts in terms of execution time: Native Image Generator and SubstrateVM runtime:

native image generator

AOT compilation logic is included. It is itself a Java program that uses the Graal compiler to compile Java class files into executable files or dynamically linked libraries.

Prior to compilation, the Native Image Generator will use points-to-analysis to explore all accessible code from the user-provided program entry. While exploring, it also executes the initialization code and saves the initialized heap into a heap snapshot when the executable is finally generated. In this way, SubstrateVM will run directly from the target program without repeated Java virtual machine initialization.

SubstrateVM runtime

An AOT-compiled target program will run on a lean runtime without HotSpot.

SubstrateVM has very little startup time and memory overhead, and because it is compiled ahead of time, the program can achieve good performance upon startup (performance peaks may be worse than JIT, but stability is better).

But it also has many problems so far:

  • It is clear that it can no longer “Write once, Run anywhere”
  • Java reflection calls apis dynamically at run time, but which interfaces are called is obviously not known at compile time until the program is running. The developer needs to explicitly tell GaalVM what code might be called by reflection (in the form of a JSON configuration file), which is disgusting and basically impossible.
  • Any HotSpot VIRTUAL machine internal interfaces (JVMTI, JVMCI, etc.) do not exist because the local image is not running on HotSpot. A large number of Agent debugging tools can not be used, nightmare!

In our current microservices architecture, local mirroring is much better than a full JVM environment + application, with stable performance, fast startup time, and less resource consumption. But only if the obstacles above can be solved.

Spring Graal Native

As mentioned above, one of the core features in GraalVM is the one that fits best with our current microservices architecture: Local mirror has many problems, one of the most important thing is a large number of third-party libraries for use in a variety of reflection and runtime of the bytecode generation and modification operations, make depend on the framework program once out of the Java virtual machine, will appear all sorts of problems, make local mirror deals. The GraalVM team made it clear that for GraalVM to be sustainable and maintainable, it would not be compatible with the existing JVM ecosystem, which would require a large number of third-party libraries to accommodate GraalVM.

3rd party libraries Graal VM native support needs to be sustainable and maintainable, that’s why we do not want to maintain fragile pathches for the whole JVM ecosystem. The ecosystem of libraries needs to Support it Natively. — Sebastien Deleuze, DEVOXX 2019

Therefore, in order to promote the compatibility of Java ecology to GraalVM, GraalVM pulled one of the most important factions of Java ecology: Spring, hence the project of Spring Graal Native. The Spring Graal Native project is designed to solve the problem of adapting Spring buckets to GraalVM.

The project is currently experimental on Github and allows you to compile SpringBoot projects into GraalVM local images. Github.com/spring-proj…

The performance comparison

The following data is based on the sample provided by Spring Graal Native, running machine configuration: I7-9700/32G

For SpringMVC project

The built-in Tomcat container contains a simple restApi

/ HotSpot Graal VM (Local image)
The startup time 1.648 s 0.075 s
Resources are occupied after startup 591M 52M
Package/compile time 12s 90s

As you can see, the boot time and resource footprint of the local image is much smaller than HotSpot (more than 10 times), but the packaging time is increased several times due to the need to compile ahead of time.

Startup time screenshot:

Runtime screenshots:

Local project renovation experiment

Even though Spring supports native image, it is difficult to transform a historical project to support local image. In the next part, I will spend some time to talk about the transformation practice.

reference

oracle/graal: GraalVM: The Run designed Faster – Anywhere GraalVM Reference Manual: the next generation of multilingual JVM GraalVM | concurrent programming network – ifeve.com GraalVM – InfoQ and its ecological system

【 Important 】 Reprint please indicate the source:Juejin. Cn/post / 685512…