Java virtual machine
| File:OpenJDK logo.svg OpenJDK logo | |
| Company type | Open-source project |
|---|---|
| Industry | Software development |
Area served | Worldwide |
| Products | Java Virtual Machine (HotSpot), Java Development Kit (JDK) |
| Owner | OpenJDK community |
| Parent | Oracle (commercial distributions) |
| Website | openjdk |
A Java Virtual Machine (JVM) is a type of virtual machine that allows computers to execute Java applications as well as other programming languages compiled into Java bytecode. The JVM is described through a formal specification designed to guarantee compatibility among different implementations, enabling developers using the Java Development Kit (JDK) to run software without worrying about underlying hardware differences.
The official reference JVM implementation is created by the OpenJDK community as an open-source project, which includes the JIT compiler known as HotSpot. Oracle’s commercially supported Java distributions are built upon OpenJDK. Another open-source JVM alternative for OpenJDK is Eclipse OpenJ9.
JVM specification
The JVM represents an abstract computing machine defined by a specification that forms part of the Java runtime environment. This specification intentionally omits specifics regarding garbage collection techniques and internal instruction enhancements, allowing diverse implementations to optimize these areas. All Java programs operate on concrete realizations of this abstract model.
Since the release of Java Platform, Standard Edition 5.0, updates to the JVM specification have been governed through the Java Community Process under JSR 924. Maintenance updates also cover modifications to the class file format as specified in JSR 202. The definitive JVM documentation, often called the blue book, serves as a reference for creating compatible implementations.
Oracle’s HotSpot remains the predominant JVM in use today. Oracle holds the Java trademark and grants licenses for certifying compliant Java implementation kits.
Garbage collectors
| Version | Default Garbage Collector | Supported Garbage Collectors |
|---|---|---|
| 6u14 | Serial / Parallel (MP) |
Serial, Parallel, CMS, G1 (E) |
| 7u4 - 8 | Serial, Parallel, CMS, G1 | |
| 9 - 10 | G1 | |
| 11 | Serial, Parallel, CMS, G1, Epsilon (E), ZGC (E) | |
| 12 - 13 | Serial, Parallel, CMS, G1, Epsilon (E), ZGC (E), Shenandoah (E) | |
| 14 | Serial, Parallel, G1, Epsilon (E), ZGC (E), Shenandoah (E) | |
| 15 - 20 | Serial, Parallel, G1, Epsilon (E), ZGC, Shenandoah | |
| 21 - 22 | Serial, Parallel, G1, Epsilon (E), ZGC, Shenandoah, GenZGC (E) | |
| 23 | Serial, Parallel, G1, Epsilon (E), ZGC, Shenandoah, GenZGC (default ZGC) | |
| 24 | Serial, Parallel, G1, Epsilon (E), Shenandoah, GenZGC, GenShen (E) | |
| 25 | Serial, Parallel, G1, Epsilon (E), Shenandoah, GenZGC, GenShen | |
| (E) = experimental | ||
Class loader
Within the JVM architecture, a class loader is responsible for loading Java class files and any compatible binary formats. This process involves three main phases:
- Loading: bringing in binary data representing a type
- Linking: verifying correctness; allocating memory for static fields with default values; optionally resolving symbolic references into direct references
- Initialization: running Java code that assigns initial values to class variables
There are three main categories of class loaders: the bootstrap class loader used for core trusted classes; the extension class loader; and the System or Application class loader. The JVM specification does not prescribe how these loaders locate or retrieve classes.
Virtual machine architecture
The JVM handles both primitive data types, such as integers and floating-point numbers, along with reference types. Initial JVM versions were limited to 32-bit architectures; consequently, the long and double types occupy two 32-bit slots. Smaller primitives like boolean, byte, short, and char are processed as 32-bit integers, utilizing specific instructions for loading and type conversion. Although boolean is treated distinctly in method signatures and arrays (where boolean[] uses one byte per element), its handling within the JVM closely resembles that of byte.
Contemporary JVM implementations, including OpenJDK HotSpot, support 64-bit platforms. This advancement enables larger heap capacities and increased thread counts, which benefits applications with extensive resource demands, albeit sometimes at the cost of slightly reduced performance compared to 32-bit JVMs.
The JVM architecture incorporates a garbage-collected heap dedicated to objects and arrays, while code segments and constants reside in a separate "method area," which may be managed independently from the heap. Each thread possesses its own call stack composed of frames containing an operand stack and local variables. The operand stack is responsible for managing computation operands and method return values, whereas local variables function similarly to registers by storing method parameters. This structure allows the JVM to operate as both a stack-based and register-based machine. During runtime, HotSpot optimizes execution by removing most stacks except for the native thread or call stack.
Bytecode instructions
The JVM provides a set of instructions designed to perform essential operations such as:
The primary objective is to maintain binary compatibility across different platforms. Each target operating system requires a dedicated JVM implementation that interprets bytecode uniformly, although internal implementations may vary. Beyond mere bytecode execution, efficiently supporting the Java core API across diverse operating systems presents significant challenges.
These instructions manipulate abstract data types rather than the native types tied to any specific instruction set architecture.
JVM languages
Languages targeting the JVM compile into valid class files that contain Java Virtual Machine instructions (Java byte code) alongside metadata. This platform-agnostic format facilitates execution across various hardware and operating systems.
Multiple languages run on the JVM platform, including adaptations of existing languages such as JRuby (Ruby) and Jython (Python), as well as languages specifically created for the JVM like Clojure, Groovy, Scala, and Kotlin. A significant benefit of this ecosystem is interoperability; libraries developed in one JVM language can be seamlessly utilized by others, enhancing overall integration.
With Java 7, JSR 292: Supporting Dynamically Typed Languages was introduced to improve dynamic language support on the JVM. This enhancement originated from the Da Vinci Machine project, which aimed to broaden the JVM’s applicability beyond Java by accommodating a wider range of programming languages.
Bytecode verifier
A fundamental principle of Java is ensuring security by preventing user applications from crashing the host environment or improperly accessing trusted code within the same JVM instance. It also guards against common programming mistakes such as out-of-bounds array access or use of uninitialized pointers. This protection is achieved through mechanisms including the class model, garbage-collected heap, and notably, the bytecode verifier.
Before execution, all bytecode undergoes verification focusing on three critical areas:
- Branch instructions must target valid code locations
- Data must be properly initialized and type-safe
- Access to private or package-private members is strictly regulated
The initial two validations occur during class loading, while enforcement of access restrictions happens dynamically at runtime.
The verifier confines bytecode sequences to valid operations—for instance, jump instructions are restricted within method boundaries. It also ensures that instructions manipulate fixed stack positions, allowing Just-In-Time (JIT) compilers to convert stack operations into register-based accesses efficiently. As a result, despite the JVM’s stack-oriented design, JIT compilation on register-centric hardware avoids performance penalties. The HotSpot Interpreter further boosts efficiency by translating bytecode directly into native register-based machine code rather than interpreting it as a stack machine; effectively serving as a JIT compiler rather than a conventional interpreter. This approach aligns with other virtual machines like the Common Language Runtime, which also specify stack-based bytecodes but implement them atop register architectures.
Early versions of the bytecode verifier contained incomplete or flawed specifications. Formalizing the JVM as a comprehensive system enables more rigorous security analysis to prevent exploits and permits optimization opportunities by omitting redundant safety checks when applications are verified safe.
Safe execution of remote code
The architecture of a virtual machine allows precise regulation of code operations inside the environment, provided the code has successfully undergone a formal bytecode verification process. This framework facilitates the secure running of untrusted remote code, a method employed by Java applets and similar secure download mechanisms. Verified bytecode executes within a confined "sandbox" environment, safeguarding users against harmful activities. Developers can attach digital signatures to applets using certificates, enabling these applets to request permissions beyond the sandbox’s restrictions, such as access to the file system or network resources.
Industries like Java Card have performed formal verification on bytecode verifiers to ensure robustness.
Bytecode interpreter and just-in-time compiler
Every distinct hardware architecture demands a tailored Java bytecode interpreter, which permits any Java bytecode program to operate on compatible hardware.
Running Java bytecode through an interpreter is slower compared to native machine code execution; however, just-in-time (JIT) compilers enhance performance by converting frequently executed bytecode segments into native machine instructions during runtime. This technique greatly boosts execution speed.
Java bytecode maintains platform independence and security. Certain JVM implementations eliminate interpreters altogether, relying exclusively on JIT compilation for running code.
JVM in web browsers
Originally, the JVM was marketed as a solution for building Rich Web Applications. By 2018, however, most web browsers had discontinued support for the Java plug-in and blocked side-loading of non-Flash plug-ins. The Java browser plug-in was officially phased out starting with JDK 9.
The NPAPI Java browser plug-in facilitated running Java applets embedded within HTML pages, allowing any language targeting the JVM to execute inside the plug-in. While applets had restricted access to user resources like microphones or 3D hardware acceleration, their influence was confined to their designated page area. This approach resembled the behavior of Adobe Flash Player.
By mid-2015, usage statistics showed that Java applets and Silverlight each accounted for only 0.1% of website usage, while Flash had declined to 10.8%.
JavaScript JVMs and interpreters
Since May 2016, JavaPoly has enabled websites to load unaltered Java libraries and invoke them directly from JavaScript code, allowing Java functionalities without requiring a local Java runtime installation.
Transpilation to JavaScript
With improvements in JavaScript execution speed and the increasing prevalence of mobile browsers that do not support plugins, converting JVM bytecode or source code into JavaScript has become an essential method for reaching wider audiences. This transpilation process utilizes existing language compilers that generate JVM bytecode.
Key JVM bytecode-to-JavaScript transpilers include TeaVM, Dragome Web SDK, Bck2Brwsr, and j2js-compiler. Notable language-specific transpilers are Google Web Toolkit’s Java-to-JavaScript compiler, Clojurescript (for Clojure), GrooScript (for Apache Groovy), and Scala.js (for Scala), all of which support cross-platform web application development using JVM languages.
See also
- Common Language Runtime
- List of Java virtual machines
- List of JVM languages
- Comparison of Java virtual machines
- Comparison of application virtualization software
- Automated exception handling
- Java performance
- Java processor
- K virtual machine (KVM)
References
- Clarifications and Amendments to the Java Virtual Machine Specification, Second Edition outlines revisions related to J2SE 5.0 and JSR 45
- JSR 45 specifies modifications to class file formats enabling source-level debugging for languages such as JavaServer Pages (JSP) and SQLJ compiled into Java