GraalVM – One VM to rule them all (the programming languages)

GraalVM is a Virtual Machine that is able to execute code from different programming languages. If you are a Java Developer this might sound familiar to you, you can run the application in Java, Scala, Kotlin, Clojure based in the JVM platform. But, GraalVM is able to run other languages like JavaScript, Node JS, Ruby, Python, R, and even C++.

An Alternative to the traditional JVM

As a JVM programming language developer, you can use the traditional Hotspot JVM or OpenJDK to run your JVM applications: Java, Scala, Kotlin. Now, you can use GraalVM as an alternative. Some advantages are:

  • It runs in the top of OpenJVM but has an extra layer that checks your code and applies some tweaks to provide better performance in your code.
  • It is Open Source. So you don’t have to deal with Oracle and its clauses that usually changes during the time.
  • You can use it as your platform to run not only JVM applications and run Node JS, Ruby and Python code in your environment.

Embedding other languages in your code

Every programming language has its advantages against other ones. For example, R is well now for its Data Analysis capabilities, and Python for a big amount of machine learning libraries, and Java because it has robust frameworks like Spring and Jakarta to create high-performance APIs.

Imagine having a Java API in Spring Framework that is able to run a script in R or Python for Data Analysis. That is possible with GraalVM, you can run embedded code in other languages in your code or make a reference to a file with the code you want to execute.

And if you think, it will affect the performance of your application because of the embedded code, it will not. Because every programming language is optimized to run in GraalVM with performance equal or better than in its own runtime.

Let’s see an example, from GraalVM’s Github. We have 2 files, a Spring-boot application in Java, and a plot.R file.

library(ggplot2)
data <<- numeric(100)

function(dataHolder) {
    svg()
    data <<- c(data[2:100], dataHolder$value)

    logHolder <- java.type("org.graalvm.demos.springr.LogHolder")
    logHolder$log(dataHolder$value, data[90:100])

    plot <- ggplot(data = data.frame(systemLoad = data, time = -99:0),
                aes(x=time, y=systemLoad, group=1)) +
                geom_line(color="orange") +
                expand_limits(x=0, y=0)
    print(plot)
    svg.off()
}
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Source;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.util.function.Function;

@Controller
@SpringBootApplication
public class SpringRApplication {

  @Value(value = "classpath:plot.R")
  private Resource rSource;

  @Autowired
  private Function<DataHolder, String> plotFunction;

  @Bean
  Function<DataHolder, String> getPlotFunction(@Autowired Context ctx)
    throws IOException {
    Source source =
      Source.newBuilder("R", rSource.getURL()).build();
    return ctx.eval(source).as(Function.class);
  }

  @RequestMapping(value = "/load", produces = "image/svg+xml")
  public ResponseEntity<String> load() {
    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.set("Refresh", "1");
    String svg = "";
    synchronized(plotFunction){
      svg = plotFunction.apply(new DataHolder(ManagementFactory.getOperatingSystemMXBean()
        .getSystemLoadAverage())
      );
    }

    return new ResponseEntity<String>(
      svg,
      responseHeaders,
      HttpStatus.OK);
  }

  @Bean
  public Context getGraalVMContext() {
    return Context.newBuilder().allowAllAccess(true).build();
  }

  public static void main(String[] args) {
    SpringApplication.run(SpringRApplication.class, args);
  }
}

And this capabilities is not only for Java code to embedded other languages. It works in any direction, you can embed R code in a NodeJS application or Java code from a Ruby application. The possibilities are huge!!!

Native Code – Great Performance

Most of these languages are interpreted by a JVM (Java, Scala, Kotlin) or are scripts interpreted on the fly (Python, R, Ruby). You can use the OAT (Ahead On-Time) feature of GraalVM and generate Native code to your machine that will bust the performance of your application.

So, you will program in your favourite language using all its feature but as a result, you will generate a binary code that runs in your machine faster than runs it in the programming language platform. And faster means up to 10x times faster, using less memory.

In the Java World we have Quarkus, the “supersonic subatomic framework” based in EE technologies, and one of its features is generate native code from Java by using GraalVM. For example:

A traditional Rest+Crud application might need 235Mb of memory and spends 9,5 seconds to start. The same application in Quarkus+GraalVM uses only 28Mb of memory and starts in just 0,042 seconds. Unbelievable!

Conclusion

This is something that as Java Developer we should keep an eye in the next years because it’s having more and more features, and right not with the features mentioned in this article it’s worthy to give it a chance and keep it in mind for our projects.

References

  • https://www.youtube.com/watch?v=GinNxS3OSi0
  • https://www.graalvm.org/docs/getting-started/
  • https://medium.com/graalvm/enhance-your-java-spring-application-with-r-data-science-b669a8c28bea
  • https://github.com/graalvm/graalvm-demos/blob/master/spring-r/
  • https://quarkus.io/
Share

You may also like...

1 Response

  1. June 9, 2020

    […] but it’s polyglot and supports more than JVM language, like NodeJS, Ruby, Python. I wrote an article some weeks ago about […]

Leave a Reply

Your email address will not be published. Required fields are marked *