Try building Java into a native module with GraalVM

Introduction

Finally, GraalVM 1.0 RC has been released! https://blogs.oracle.com/developers/announcing-graalvm

People in the Java area know that it is the next-generation platform around AOT of Java 9 and JIT of Java 10, and people of Ruby know it as the explosive Ruby environment (Truffle Ruby).

On the official website

GraalVM is a universal virtual machine for running applications written in JavaScript, Python 3, Ruby, R, JVM-based languages like Java, Scala, Kotlin, and LLVM-based languages such as C and C++. https://www.graalvm.org/

The purpose of the VM environment is to create a unified VM for all languages and utilize assets such as back tools and JIT. I feel the same idea as ORM of IBM / Eclipse.

You can do various interesting things, but one of the features is that you can natively compile JVM-based languages. This can significantly improve Java, which is famous for its bad footprint at startup. It can also be packaged as a single package. There was a nostalgic tool called GCJ when it came to AOT-compiling Java to create a binary, but it doesn't follow the latest Java already, so I think it's virtually unique.

Currently, there are Community Edition and Enterprise Edition. For the time being, I created a CE version of Docker environment so that I can try it quickly without installing it, so I will use that this time. https://hub.docker.com/r/koduki/docker-graalvm/

Build into a native module

Let's build a simple code into a Linux native binary. The code to build is below.

public class HelloWorld {
  public static void main(String args[]){
    System.out.println("Hello, World");
  }
}

Check the version number that doubles as Pull with the following command. You can see that it is GraalVM.

$ docker run -it -v "`pwd`:/src" koduki/graalvm:1.0.0-rc1  java -version
openjdk version "1.8.0_161"
OpenJDK Runtime Environment (build 1.8.0_161-12)
GraalVM 1.0.0-rc1 (build 25.71-b01-internal-jvmci-0.42, mixed mode)

Then it is usually compiled and executed in Java.

$ docker run -it -v "`pwd`:/src" koduki/graalvm:1.0.0-rc1 javac HelloWorld.java
$ docker run -it -v "`pwd`:/src" koduki/graalvm:1.0.0-rc1 java Hello, World

Obviously, it says Hello, World. Now let's compile this into a Linux binary.

$ docker run -it -v "`pwd`:/src" koduki/graalvm:1.0.0-rc1 native-image HelloWorld
Build on Server(pid: 9, port: 26681)*
   classlist:   4,335.15 ms
       (cap):   1,257.90 ms
       setup:   3,411.13 ms
  (typeflow):  12,345.25 ms
   (objects):   3,497.83 ms
  (features):      89.48 ms
    analysis:  16,130.07 ms
    universe:     541.30 ms
     (parse):   4,822.63 ms
    (inline):   2,370.80 ms
   (compile):  20,626.56 ms
     compile:  28,372.55 ms
       image:   1,507.64 ms
       write:     489.70 ms
     [total]:  54,945.94 ms
$ docker run -it -v "`pwd`:/src" koduki/graalvm:1.0.0-rc1 ./helloworld
Hello, World

You now have a binary called hello world. The execution result is also the same. Now let's see the difference in startup footprint because it is a native binary.

Overhead is large if you go through Docker, so go into docker and check.

$ docker run -it -v "`pwd`:/src" koduki/graalvm:1.0.0-rc1  /bin/bash
[root@d16c0ed04d03 src]# time java HelloWorld
Hello, World

real	0m0.167s
user	0m0.070s
sys	0m0.070s
[root@d16c0ed04d03 src]# time ./helloworld 
Hello, World

real	0m0.031s
user	0m0.000s
sys	0m0.000s

You can see that the binary version runs faster. Since it is simple to make, you can think of this as a difference in overhead such as VM startup rather than execution speed.

Summary

For the time being, I tried to build Java into binary using native-image of GraalVM. Although it is not written in the article, it can be used as a substitute for fat-jar because it makes one binary properly even in multiple classes.

It doesn't work with dynamic module loading as @sonodar tried in the article "I tried GraalVM" So, it seems to be difficult to run a web application that uses Spring Boot etc. with a single binary instead of fat-jar. At the moment.

However, since the footprint has become smaller, it is quite a merit for me to make it easier to create CLI tools in JVM-based languages such as Scala. Scripts are fine, but writing in Java is also convenient for maintainers to collect. I would like to check the behavior in combination with some libraries.

Also, since this article is the CE version, I tried it on Linux, but I was able to build the Mac with the EE version without any problems. If you can cover Windows with this, it seems that you can do various different things.

Then Happy Hacking!

Recommended Posts

Try building Java into a native module with GraalVM
Try debugging a Java program with VS Code
Run Scala with GraalVM & make it a native image
Try DB connection with Java
Try gRPC with Java, Maven
Java program to resize a photo into a square with margins
[Beginner] Try to make a simple RPG game with Java ①
Try developing a containerized Java web application with Eclipse + Codewind
Build a Java project with Gradle
Try to speed up Java console program startup with GraalVM native-image
Try using Redis with Java (jar)
Try bidirectional communication with gRPC Java
Let's try WebSocket with Java and javascript!
Try running a Kubernetes Job from Java
Try building a GPU container on GCP.
Try making a calculator app in Java
Split a string with ". (Dot)" in Java
Try managing Java libraries with AWS CodeArtifact
Try using the Wii remote with Java
[Java] Module
Try building Express + PostgreSQL + Sequelize with Docker [Part 2]
Run Rust from Java with JNA (Java Native Access)
Read a string in a PDF file with Java
Create a CSR with extended information in Java
Create a simple bulletin board with Java + MySQL
[Windows] [IntelliJ] [Java] [Tomcat] Create a Tomcat9 environment with IntelliJ
Let's create a timed process with Java Timer! !!
Try to create a bulletin board in Java
Try to link Ruby and Java with Dapr
[Java] Create a collection with only one element
Try building Express + PostgreSQL + Sequelize with Docker [Part 1]
Prepare a scraping environment with Docker and Java
Try to implement TCP / IP + NIO with JAVA
Try drawing a cube with View and Layer
I tried to break a block with java (1)
Build a Java development environment with VS Code