GraalVM vs HotSpot: Two JVM Implementations Compared

HotSpot is the standard JVM in OpenJDK, written in C and C++. GraalVM is a JDK distribution that replaces HotSpot's C2 JIT compiler with Graal, a JIT written entirely in Java, and adds polyglot support and Native Image (AOT compilation to native executables). Both run the same Java bytecode; the difference is in the implementation and the extended capabilities.

HotSpot: the standard JVM

HotSpot is the production JVM inside OpenJDK, which is the open-source basis for Oracle JDK, Amazon Corretto, Eclipse Temurin, Microsoft Build of OpenJDK, and others. The interpreter and JIT compilers are written in C++; the garbage collectors, class-loading mechanism, and much of the JVM infrastructure are also C++, with some C in the lower-level platform integration.

HotSpot uses a tiered compilation model. Cold code starts in the interpreter. Methods that are called often are promoted first to the C1 (client) compiler, which produces lightly optimized machine code quickly, then potentially to the C2 (server) compiler, which applies aggressive optimizations including inlining, loop unrolling, and speculative devirtualization. C2 is a large, complex piece of C++ that took Oracle engineers years to develop.

HotSpot's garbage collectors include: Serial GC (single-threaded, small heaps), Parallel GC (throughput-focused), G1 GC (the default since Java 9, balancing throughput and latency), ZGC (sub-millisecond pauses, generational since Java 21), and Shenandoah (concurrent compaction, contributed by Red Hat). All are written in C++.

GraalVM: a JVM with a Java-written JIT

GraalVM is a JDK distribution developed by Oracle Labs (and the open-source TruffleRuby / Graal community). Its defining property is that the Graal JIT compiler is written in Java. It uses the JVM Compiler Interface (JVMCI), which was added to HotSpot in Java 9 to allow plugging in a custom JIT compiler. Graal loads as a regular Java class and replaces the C2 tier.

Writing the JIT in Java has several advantages. Java engineers can contribute to the JIT without knowing C++. The compiler can apply sophisticated speculative optimizations using Java's own type system to represent its abstract interpretation. Graal is also the technology behind Oracle's claim that "GraalVM can run faster than HotSpot's C2" for some workloads: the better escape analysis and inlining decisions possible in Java outweigh the overhead of the JIT itself being managed code.

GraalVM is not a single product but a distribution: it ships HotSpot with Graal replacing C2, plus additional capabilities built on top of the Truffle framework.

Native Image: AOT compilation for Java

GraalVM's most distinctive feature is Native Image: a build-time tool that statically analyzes a Java application and compiles it ahead-of-time to a self-contained native executable. The executable does not include a JVM; instead, it includes a minimal runtime (Substrate VM) written in Java that handles garbage collection and threading.

Native Image eliminates JVM startup time: a native Spring Boot application that takes 3 to 5 seconds to start under HotSpot might start in under 100 milliseconds as a native binary. This matters for serverless functions, CLI tools, and container-based deployments where startup latency is a first-class concern.

The tradeoff: Native Image requires closed-world assumption (all reachable classes must be known at build time), which breaks dynamic class loading, reflection, and serialization patterns common in older Java frameworks. Modern frameworks like Micronaut, Quarkus, and (with careful configuration) Spring Boot have addressed this with build-time reflection registration.

Polyglot: running other languages on Truffle

GraalVM includes the Truffle language implementation framework, which lets other language runtimes run on GraalVM and benefit from the Graal JIT. Truffle-based language implementations include TruffleRuby (Ruby), Graal.js (JavaScript), GraalPy (Python), and FastR (R). When a Truffle language's code gets hot, Graal JIT-compiles it to native machine code.

This makes GraalVM genuinely polyglot at the runtime level, not just at the API level. A Ruby method called frequently from Java can be JIT-compiled and inlined into the calling Java code's native compilation. HotSpot has no equivalent capability.

Comparison

PropertyHotSpot JVMGraalVM
JIT compilerC1 and C2 (written in C++)C1 and Graal (C1 in C++, Graal in Java)
Base languageC and C++C++ (HotSpot base) + Java (Graal, Substrate VM)
AOT compilationNo (jaotc was experimental, removed in Java 17)Yes: Native Image via Substrate VM
PolyglotNoYes: Truffle-based Ruby, Python, JavaScript, R
Startup timeStandard JVM startup (seconds for large apps)Milliseconds for native image builds
Peak throughputExcellent (C2 is highly mature)Equal or better for some workloads
LicenseGPL v2 with classpath exception (OpenJDK)Community Edition: GPL; Enterprise: Oracle license

Which to use

Use HotSpot for established enterprise Java applications where compatibility and operational stability matter. It has the longest track record, the most production deployments, and C2 is an extremely well-tuned JIT for traditional long-running services.

Use GraalVM when you need Native Image (serverless, containers, CLI tools), when you want to run Ruby or Python workloads on the same JVM as Java, or when you want to experiment with Graal's JIT on workloads where C2's analysis limits performance. GraalVM Community Edition (free, GPL) is suitable for most use cases.

The significance of writing a JIT in Java

The Graal JIT being written in Java is more than a curiosity. It means a JVM JIT compiler can be compiled and optimized by the JVM itself: Graal is a Java program that runs on the JVM and gets JIT-compiled by... Graal. This self-application is called partial evaluation and it is the basis of the Futamura projections, a theoretical framework for deriving efficient interpreters and compilers from each other. The Truffle framework exploits partial evaluation to JIT-compile language interpreters: you write a simple interpreter in Java, Truffle + Graal partially evaluate it against the program being interpreted, and the result is machine code for that specific program.

This is why Truffle-based language implementations can reach competitive performance without writing a JIT compiler from scratch. TruffleRuby and GraalPy do not implement their own compilation pipelines; they implement interpreters that Graal transforms into efficient native code automatically. This represents a different approach to the "what language is the runtime written in?" question: the runtime is Java, and the JIT compiler is also Java, but the JIT-compiled output is architecture-native machine code.

See the Java language page for the full implementation graph, including the Graal JIT relationship.

Explore Java Relationships in Graph →