GraalVM: The Capsule Corp of Modern Development
Originally published on Shuru Blog
Table of Contents
- 🐰 Introduction to GraalVM
- Overview of the GraalVM
- The need for the GraalVM
- Benefits at a Glance - 🧠 Understanding How Native Java Code Executes.
- 🕸️ GraalVM Architecture:
- 🔑 Key Features of GraalVM
- 💨 Ahead Of Time Compilation:
- 🏃 Runtime Optimisations:
- 🎖️ Polyglot Capabilities:
- 🥊 GraalVM Vs JVM
- 🏛️ Major Enterprises and Their Journey with GraalVM
- 🏳️ Conclusion
Introduction to GraalVM 🐰
Overview of the GraalVM
GraalVM is a high-performance universal virtual machine offering a significant advancement in the Java ecosystem, originally started as a research project at Oracle Labs in 2011. It stands out for its ability to execute applications written in a variety of programming languages, including JVM-based languages like Java, Scala, and Kotlin, as well as JavaScript, Python, Ruby, R, and LLVM-based languages such as C and C++.
Its innovative GraalVM compiler, compatible with both the standard Java HotSpot VM and OpenJDK, allows for ahead-of-time compilation of Java applications into standalone binaries. These binaries boast remarkably faster startup times—up to 100x faster—peak performance without the need for warm up, and reduced memory and CPU usage. Additionally, GraalVM enhances security by minimising the application’s attack surface through the exclusion of unused code and restrictions on dynamic Java features.
Supported by popular microservices frameworks and cloud platforms, GraalVM facilitates efficient resource use and interoperability among different programming languages within projects, offering developers a versatile tool for optimising application performance and deployment.
The need for the GraalVM
- Performance Enhancement: Despite JVM’s efficiency, there was a need for further optimization, especially regarding startup time, peak performance, and memory usage. GraalVM addresses these by introducing a more advanced Just-In-Time (JIT) compilation and ahead-of-time (AOT) compilation options, significantly improving performance.
- Polyglot Programming: The industry’s shift towards using multiple programming languages within the same project highlighted the limitations of JVM’s predominantly Java-focused ecosystem. GraalVM was designed to support a variety of languages (e.g., JavaScript, Ruby, and Python) natively, facilitating smoother integration and development processes.
- Modernising Java: While Java remains a powerful and widely used language, the perception of it being “legacy” software necessitated innovation to maintain its relevance. GraalVM offers a pathway to modernise Java-based applications, making them more efficient and adaptable to current technological trends.
- Enhanced Tooling and Debugging: With the aim of improving developer productivity, GraalVM integrates enhanced tooling for debugging and profiling, which are applicable across supported languages. This unified tooling approach reduces complexity and streamlines development workflows.
- Cloud and Microservices Optimization: The rise of cloud computing and microservices architectures demanded more from the underlying platforms in terms of resource efficiency and scalability. GraalVM’s lightweight nature and efficiency make it well-suited for these environments, offering reduced resource consumption and faster deployment times.
- Security Improvements: Addressing security in a multi-language environment, GraalVM provides mechanisms to safely execute code, reducing the surface for vulnerabilities and enhancing the security posture of applications.
Benefits at a Glance
- Performance Optimization: GraalVM dramatically enhances application startup times and runtime efficiency, crucial for cloud and microservices where quick scalability and resource efficiency are paramount.
- Cross-Language Interoperability: It offers a unified platform for executing multiple programming languages seamlessly, facilitating easier integration and interoperability between diverse components.
- Security Enhancements: GraalVM enhances security by removing unused code and limiting dynamic Java features to build time, reducing the application’s attack surface.
- Resource Efficiency: It optimises resource use, leading to lower infrastructure costs and a reduced environmental impact, aligning with sustainability goals.
- Support for Modern Infrastructure: GraalVM supports popular microservices frameworks and major cloud platforms, ensuring developers can leverage its benefits in various deployment environments.
- Sandboxing: For running untrusted code (third parties lib or plugins etc), GraalVM can provide sandboxing capabilities, limiting what the code can do and access on the host system. This significantly reduces the risk of malicious code causing harm
🧠Understanding How Native Java Code Executes.
Before we explore the revolutionary capabilities of GraalVM, it’s essential to understand the traditional journey of Java code from creation to execution. This journey not only sets the stage for appreciating the innovations of GraalVM but also provides a baseline understanding of Java’s execution model, contrasting it with languages like C++ and paving the way for a deeper appreciation of the improvements GraalVM offers.
The Journey of Java Code: From Source to Execution
Writing and Compiling Java Code
The initial steps in Java development are familiar to all programmers: writing the source code. Java developers craft their applications using the Java programming language, which is then compiled, not into machine code, but into an intermediate form known as bytecode. This is a crucial divergence from languages like C++, where the source code is compiled directly into machine code specific to the target operating system and processor.
Bytecode: Java’s Portability Secret
Java’s use of bytecode is a cornerstone of its write-once-run-anywhere philosophy. Unlike machine code, bytecode is not tied to any specific type of hardware. This means a Java program compiled on one machine can be transferred to and run on another machine without modification, provided that the second machine has a Java Virtual Machine (JVM) installed.
The Role of the Java Virtual Machine (JVM)
The JVM is where the magic happens, transforming platform-independent bytecode into machine-specific instructions that can be executed by the host computer’s CPU. This process involves several steps, including class loading, bytecode verification, and just-in-time (JIT) compilation.
Class Loading and Bytecode Verification: The JVM loads the class files (containing bytecode) and verifies the bytecode to ensure it’s valid and secure to execute. This step prevents malicious code from damaging the host system.
Just-In-Time (JIT) Compilation: While the JVM can interpret bytecode directly, interpreting alone is not the most efficient way to execute Java programs. Enter JIT compilation, a process where the JVM compiles bytecode into native machine code at runtime, significantly speeding up execution by leveraging the host hardware’s capabilities.
- JDK includes the javac compiler which compiles the code to the byte code
- JRE is an installation package that provides env to only run the programs
- It Consists of:
- deployment technologies
- user interface toolkits
- integrations lib
- base lib
- JVM
IN SUMMARY, THIS IS WHAT THE NATIVE EXECUTION LOOKS LIKE:”
Java source code < JDK < Bytecode < JVM
AND THIS IS WHAT THE GraalVM EXECUTION LOOKS LIKE IN SIMPLE TERMS
Java source code < graal JDK < Bytecode < Graal VM
🕸️GraalVM Architecture:
GraalVM stands out with its unique architecture designed to support polyglot programming and deliver high-performance applications. The architecture is structured in three key layers:
Java HotSpot VM
At the base of the GraalVM architecture is the Java HotSpot VM, which is the foundation for running Java applications. It provides the robustness and mature features that Java developers are accustomed to, including garbage collection and thread management.
GraalVM Compiler
Sitting above the Java HotSpot VM is the GraalVM Compiler, which is a modern, high-performance dynamic compiler designed to execute JVM languages with improved efficiency. It is also responsible for compiling other supported languages into bytecode that the Java HotSpot VM can execute.
Language Implementation Framework
The top layer is the Language Implementation Framework, which is where GraalVM’s polyglot nature comes to life. This framework uses the Truffle API, allowing for the implementation of different language interpreters. Each language (Java, Scala, JavaScript, Ruby, R, WebAssembly, C/C++, and others) is represented here, showcasing GraalVM’s ability to run code written in various languages in a single runtime environment.
In essence, this architecture allows GraalVM to execute not only JVM-based languages but also other languages such as JavaScript, LLVM-based languages, and even dynamic languages, all within the same runtime.
This seamless interoperability is a key advantage for developers looking to leverage the strengths of different programming ecosystems in a unified platform.
🔑Key Features of GraalVM
Ahead Of Time Compilation:
GraalVM’s Ahead-of-Time (AOT) Native Image Compilation transforms how we deploy Java applications, making them faster, smaller, and more secure.
The Process:
GraalVM takes your Java code and converts it into a native executable, bypassing the traditional route of bytecode and JVM interpretation. This direct approach eliminates the need for just-in-time (JIT) compilation at runtime, allowing your application to launch instantly and run at full speed from the get-go. It’s a bit like creating a custom key for each lock (system and architecture) you need to open, ensuring a perfect fit every time.
The Key Benefits
- Quicker Startups: Applications launch immediately, with no warm-up delays, enhancing performance from the outset.
- Smaller Application Size: The native binaries are more compact, using less memory, which makes your apps more efficient.
- Enhanced Security: By removing unused code, GraalVM minimises security vulnerabilities, offering a tougher shell against cyber threats.
- Framework Compatibility: Continue using your favourite frameworks like Spring and Quarkus without hassle.
- Optimal for Containers: The compact, efficient binaries are tailor-made for container environments, boosting startup times and security.
- Polyglot Support: Mix and match languages in your Java-based apps for greater flexibility in development.
Why It Matters
For developers, GraalVM’s AOT compilation means less time worrying about performance optimization and security, and more time focusing on building great features. For users, it translates to using applications that are not only faster and more responsive but also require less system resources and offer improved security. Whether you’re developing for the cloud, microservices, or containerized environments, GraalVM equips you with a powerful tool to elevate your Java applications.
Some SetBacks with AOT:
When using GraalVM’s Ahead-of-Time (AOT) compilation to convert Java applications into native executables, developers face a unique challenge due to the “closed-world” assumption. This assumption requires the compiler to be aware of all classes that might be used at runtime from the get-go. Dynamic features of Java, like reflection, dynamic class loading, and JNI, complicate this because they introduce classes and methods at runtime, which the static analysis of AOT might miss.
For example, consider a scenario where a Java application dynamically loads a class based on a specific condition:
if (todayIsHoliday()) {
Class<?> holidayClass = Class.forName("HolidaySpecial");
holidayClass.getMethod("celebrate").invoke(null);
}Code language: JavaScript (javascript)
In this case, AOT compilation wouldn’t automatically include “HolidaySpecial” in the executable unless it’s explicitly known at compile time. This is because the compiler can’t predict runtime conditions like “todayIsHoliday()”
The Solution? Developers need to manually specify such dynamically loaded classes through metadata (like JSON files), ensuring they’re included in the final build. This makes the application “AOT-ready” but also adds an extra step in the development process, requiring thorough documentation and configuration for each dynamically referenced class or method.
This balancing act between optimising for performance and maintaining the dynamic capabilities of Java is a key consideration with AOT compilation, making it essential for developers to plan and adapt their code and dependencies accordingly for successful native binary generation with GraalVM.
🏃Runtime Optimisations:
GraalVM not only transforms Java applications through Ahead-of-Time (AOT) compilation but also offers significant runtime optimization capabilities.
These optimizations enhance performance and efficiency dynamically as your application runs. Here are a few methods GraalVM employs for runtime optimization:
- Escape Analysis: GraalVM analyses the scope of object references to determine if an object escapes the method or thread it was created in. If it doesn’t escape, GraalVM can optimise away the allocation, reducing overhead and improving performance. This technique can lead to significant reductions in garbage collection pressure.
- Inlining: This optimization involves integrating the code of called methods directly into the caller’s code, eliminating the overhead of method calls. GraalVM uses sophisticated heuristics to decide which methods to inline, enhancing execution speed, especially in hot code paths.
- Dead Code Elimination: GraalVM removes code that doesn’t affect the program’s outcome, such as variables that are never read after being set. This streamlining of the executable code minimises the footprint and improves execution time.
- Loop Unrolling: By duplicating the code within loops a fixed number of times, GraalVM reduces the overhead of loop control and increases the efficiency of tight loops, which is particularly beneficial for loops with a small, predictable number of iterations.
NOTE: Code using more modern Java features like Streams or Lambdas will see greater speedups as this type of code involves a significant number of such non- or partially-escaping objects. Code that is bound by things like I/O or memory allocations that cannot be removed by the compiler will see less improvement REF
🎖️Polyglot Capabilities:
GraalVM’s polyglot capabilities represent a significant leap forward in the world of software development, breaking down the barriers between different programming languages. Let’s dive into what polyglot programming is, why it’s beneficial, and how GraalVM enables these advantages through its unique architecture.
What is Polyglot Programming?
Polyglot programming refers to the ability to use multiple programming languages within a single project or system. This approach allows developers to choose the best language for each task, whether it’s for data analysis, system scripting, or building web interfaces. Traditionally, integrating multiple languages in one project could lead to significant overhead and performance challenges due to the limitations of virtual machines (VMs) and the need to manage separate language environments.
The Benefits of Polyglot Programming
The main advantage of polyglot programming is flexibility. Developers can leverage the strengths and libraries of various languages, optimising each part of an application for performance, ease of development, or functionality. For instance, they might use Python for machine learning tasks, JavaScript for frontend development, and Java for backend systems.
How GraalVM Revolutionizes Polyglot Programming
GraalVM addresses these challenges head-on by offering seamless polyglot programming capabilities. Here’s how it changes the game:
- Unified Runtime: GraalVM provides a single runtime environment that supports multiple languages, including all JVM-based languages (like Java, Scala, and Kotlin), JavaScript, LLVM-based languages such as C and C++, and dynamic languages like Ruby and Python. This eliminates the need to juggle multiple VMs and runtimes.
- Access to Libraries Across Languages: Developers can use libraries and frameworks from one language in another with minimal overhead, opening up a wealth of functionality that was previously cumbersome to integrate.
- Reduced Overhead: By sharing underlying system resources such as memory management (garbage collection) and compilation optimization across languages, GraalVM reduces the performance penalties typically associated with polyglot applications.
- Truffle Framework: At the heart of GraalVM’s polyglot prowess is the Truffle language implementation framework. Truffle is a toolkit for building programming language interpreters, and it’s what allows GraalVM to support a wide array of languages efficiently. It provides a set of high-level APIs for language implementation, which, when used in conjunction with GraalVM, can execute code from different languages within the same VM instance efficiently.
Real-World Implications
For developers, GraalVM’s polyglot capabilities mean the ability to build more efficient, innovative, and complex applications with fewer compromises. Whether it’s leveraging R for statistical computing, Python for scripting, or any other language mix, GraalVM facilitates a level of interoperability that was previously difficult to achieve. This makes it an invaluable tool for modern software development, especially in environments where performance and flexibility are paramount.
🥊 GraalVM Vs JVM
🏛️Major Enterprises and Their Journey with GraalVM
GraalVM is utilised by a diverse range of companies across various industries and countries. Notable firms that have adopted GraalVM include major tech companies, financial institutions, e-commerce giants, and more. Here are some examples:
- Facebook has integrated GraalVM to enhance the performance of their big data services like Spark, achieving significant improvements in workload speed and resource usage.
- Twitter has realised substantial savings in CPU usage and reduced the number of machines required by running their services on GraalVM.
- Standard Chartered Bank uses GraalVM for fast Java application starts and to streamline their cloud deployments.
- NetSuite, a provider of cloud-based business management services, uses GraalVM to build machine learning models within Java applications.
- Alibaba employs GraalVM’s Native Image technology for faster startup times of Java applications.
- Goldman Sachs is modernising their proprietary programming language for critical financial applications using GraalVM.
- Oracle Cloud Infrastructure and various Oracle services have incorporated GraalVM to improve performance and reduce resource consumption.
- Disney Streaming has used GraalVM to significantly reduce the cold start times of their serverless Java workloads.
- Adyen, a payment processing platform, has adopted GraalVM to modernise and run its applications in the cloud.
Additionally, companies like EPAM Systems, Red Hat, VMware, and others across the United States and globally have incorporated GraalVM into their tech stacks.
🏳️Conclusion
GraalVM emerges as a compelling option when seeking faster startup, smaller memory footprints, native images, and polyglot capabilities.If your priorities include cloud-native deployments, microservices, or integrating code from other languages, GraalVM is worth serious consideration.
Ultimately, the best choice depends on your project’s priorities and the trade-offs you’re willing to accept in terms of potential tooling limitations and the experimental nature of some GraalVM features.
Reference: Why GraalVM