Quarkus - A Supersonic, Subatomic Java

Jayamal Jayamaha
Sysco LABS Sri Lanka
7 min readOct 19, 2023

--

I am an avid Java developer and have been working with Springboot for over three years. It has been my go-to framework for most of my projects.

However, recently a colleague introduced me to the Quarkus framework.

Initially, I was skeptical and asked why I should switch to Quarkus when I already have a great framework like Springboot. But, since Quarkus is relatively new, I decided to learn it more thoroughly.

Before we dive into the Quarkus, we need to learn some important things to understand the ground level that holds the base for Quarkus.

What is GraalVM

GraalVM is a Polyglot runtime environment that can be used with multiple programming languages. GraalVM uses high performance Just in Time(JIT) and Ahead of Time(AOT) compilation techniques to build the applications as high-performance and low startup time native executables.

Before going further let’s clarify some important concepts.

Polyglot runtime environment
We can use GraalVM to compile and build not only for Java but for other programming languages as well. GraalVM contains language specific runtime components and libraries so we can use this same run time environment to run the application which were written in different languages like C,C++,Python,Ruby, JavaScript etc.

Just in Time compilation (JIT)
This is a compiler that will compile byte code to machine code and this will happen during application runtime. This compiler will read the byte code and run it through a interpreter and also will optimize the code with some advanced optimization concepts. Also this JIT compilation will be used by the languages with dynamic class loading and languages which uses reflection like Java.

Ahead of Time compilation (AOT)
As the name suggest this compiler will compile the code to machine code without compiling it to byte code and it will create a executable out of the code. After that this executable can be run on a specific system without a need of any kind of virtual machine like JVM. The compiled executable will be more efficient, less memory usage, has faster startup time and use as a container friendly native executable than the application that uses JIT compilation. But in this method we need to do some additional configurations if our code need to use dynamic class loading and reflection features.

GraalVM uses both techniques when compiling a project. As we discuss Java mostly in this article, we can create a jar by compiling Java code with JIT compiler and can be run on the GraalVM, or we can create a native executable by compiling the code with AOT compiler and can be used in containerized environments. However, the JIT compiler of this GraalVM will compile the Java code to byte code in a more efficient way than the JIT compiler in JVM.

What is Quarkus

Quarkus is a Kubernetes-Native Java framework, which uses GraalVM and HotSpot techniques to develop. Since this is using GraalVM, all the Optimization features and advanced features of GraalVM are available in Quarkus as well.

How has Quarkus become so remarkable?

Low startup time and low memory footprint
Since Quarkus uses GraalVM by default instead of JVM, the optimized compilation capabilities that GraalVM has will be applicable to this Quarkus as well. Quarkus will implement this low startup time and low memory footprint by leveraging AOT compilation of GraalVM. Also when we run the Quarkus application as jar file, it will have a low startup time and low memory foot print as well. This will happen because GraalVM do some advance optimization techniques when compiling the Java code to bytecode rather than JVM.

Low package size
Since Quarkus can leverage the native executable generation capability of GraalVM, We can use AOT compilation and build a native executable, which is more lightweight by size than a jar file in Springboot.

Container and orchestration friendly
Quarkus is Kubernetes-Native framework, so at the inside of the framework, it has a great support to Kubernetes and orchestration. Secondly, since GraalVM can create native executables, we can easily containerize it and run the application as containers. Also since the native executable is small in size, we can easily create small sized images and store it in a Docker registry.

Low memory and CPU usage
Since we can leverage AOT compilation of GraalVM, we can create native executables. Afterwards our application can run on a system by itself without GraalVM. So The total memory and CPU that will be used for the application will be very less since there are no JIT compilation processes need be executed when we use native executables.

While we may delve into the advantages of AOT compilation, it’s essential to recognize the existence of drawbacks. Just like with anything else, there are both pros and cons to consider, and striking a balance is crucial.

Drawbacks of AOT compilations

Before discussing the drawbacks of AOT compilations, first, we need to look at why we need a concept called JIT compilation for Java applications. The main reason is the dynamic behavior of Java and JVM

Pholimopshism and Late Binding
To understand this concept let's see some frequently used concepts of Java below;

interface Shape {
void draw();
}

class Circle implements Shape {
public void draw() {
// Circle drawing logic
}
}

class Rectangle implements Shape {
public void draw() {
// Rectangle drawing logic
}
}

public class Main {
public static void main(String[] args) {
Shape shape = new Circle();
shape.draw();
}
}

Using interfaces and implementing them by concrete classes is a fundamental concept of Pholimopshism in Java, but here, the assigning of Circle object to Shape type will happen in runtime, so our JVM doesn't know what “draw()” method needs to be run in advance until it reaches runtime.

At the runtime, the JIT compiler will decide which “draw()” method (either draw method of interface or draw method of circle class) to be executed, it will then generate the machine code to that specific “draw” method and then run it through the interpreter. Therefore, the JIT compiler will decide the most optimized and specific way to dynamically execute the above code block at runtime. This process is called Late Binding

Achieving this can be somewhat challenging in AOT compilation since it’s difficult to pre-determine and bind the exact drawing method to be executed at runtime in this application.

Use of Reflection and Dynamic Class Loading
JIT compiler frequently uses Reflection and Dynamic Class loading when it compiles byte code to machine code. First, the JIT compiler needs to decide what kind of classes needs to be loaded at a specific point of execution, in order to execute a particular piece of code. Then the JIT compiler needs to decide which methods should be executed at that particular point of execution. So, to obtain those details about methods and variables, the JIT compiler uses Reflection.

Loading only necessary classes without generating machine code for all the classes in advance, will mean more efficient and optimized execution of the program. This is because we load only the required machine code of classes to memory at a specific point of execution.

On the other hand, JVM needs to decide which classes and their methods need to be loaded, based on dynamic configurations and use inputs at runtime. To do that JIT compiler need a concept called Reflection. JIT uses Reflection to load and read metadata of classes, load methods and execute them in runtime, and extract and modify variables based on dynamic configurations at runtime.

Sometimes above mechanisms won't work as efficiently as in the JIT compiler when we use the AOT compiler. JIT compiler will do advanced optimization steps depending upon the situation of execution, but in AOT compilation, the compiled code may not be optimized very well in the above kind of scenarios. Once more, there are methods to configure this Reflection aspect in AOT. In Quarkus, we can employ specific annotations for this purpose. Through this configuration approach, we can also alleviate the drawbacks above.

Limitations of Quarkus

While Quarkus does offer noteworthy solutions, it’s important to note that it comes with certain limitations. Being a relatively new framework introduced around 2019, and as of the time of writing this article, it’s prudent to be aware of these limitations when making technology stack decisions for a project in order to maximize the benefits for an organization.

Learning curve and limited eco system
There is a considerable learning curve for the Quarkus, because this is a new framework and it has a limited community when compared to Springboot. You can find tons of reference materials and videos for Springboot but for Quarkus it is quite low. You may need to take time to resolve if you come across issues or misunderstandings.

Build time
Since Quarkus uses some advanced optimization techniques in build time, and uses AOT compilation to generate the native image, the build time of this Quarkus application will be high. Also building processes may require some high resource utilization as well (RAM and CPU). If it can’t allocate the required resources, the build process may fail. The build process is a kind of resource and time intensive process in Quarkus.

May contain bugs
Since this is relatively a new framework, it has not covered all the edge cases when we use this in production. So this may contain some bugs. Also this is a open source project, the community will take some time to report and fix those bugs. The lack of production experience in any kind of framework should be highly considered when you consider to use this framework to build enterprise grade software in your organization.

Conclusion

As we can now learn, Quarkus is a very good framework for building enterprise-grade applications with great performance by using Reactive and NonReactive styles simultaneously. But, since I am a Springboot lover, we have the option to use GraalVM with AOT compilation and achieve the same level of performance and startup time benchmarks as Quarkus in the Springboot framework as well. The motivation for this article is to introduce and draw your attention to this new framework and to its very important base concepts. I will write about the new GraalVM and AOT features in Springboot 3 in another article.

--

--