Java How Jvm Works
Java How Jvm Works
July 3, 2025
how modern JVMs (like HotSpot/OpenJDK, OpenJ9, or GraalVM) work?
- 这是一个经过多层次抽象的软件系统。
- 想要彻底了解,需要理解每一层,显然要知道每一层是做什么的。
- 每一层的边界在哪里。
- 问题出于哪一层。
1. Java Layer
- Java Code: application code (e.g.,
MyClass.java
) is compiled into bytecode (.class
files). - Bytecode Execution: The JVM interprets this bytecode or compiles it to native machine code using a Just-In-Time (JIT) compiler (e.g., C1/C2 in HotSpot, or the newer Graal compiler).
- Java APIs: Even core Java APIs (e.g.,
java.lang.Object
,java.io.File
) are implemented in Java but rely on native methods (via JNI/native
keywords) for low-level operations.
2. C/C++ Layer (JVM Implementation)
- JVM Internals: The JVM itself (e.g., HotSpot) is primarily written in C++. This layer handles:
- Memory Management: Garbage collection (G1, ZGC, Shenandoah, etc.).
- Threading: Thread scheduling and synchronization.
- JIT Compilation: Translating bytecode to optimized machine code.
- Class Loading: Parsing
.class
files and verifying bytecode.
- JNI (Java Native Interface): When Java code calls
native
methods (e.g.,java.lang.Thread.start()
), the JVM delegates to C++ code via JNI. This bridges Java and native code. - OS Abstraction: The JVM uses platform-specific C/C++ code (e.g.,
os_linux.cpp
,os_windows.cpp
) to handle OS differences.
3. System Call Layer
- OS Interaction: The JVM’s C++ code interacts with the operating system through system calls (e.g.,
read()
,write()
,mmap()
). These are often wrapped by:- Standard Libraries (e.g., glibc on Linux, MSVCRT on Windows).
- Direct Syscall Wrappers: For performance-critical paths (e.g., thread scheduling via
futex()
on Linux).
- Kernel Mode: System calls transition into kernel mode to access hardware resources (e.g., file I/O, network sockets, memory allocation).
Visualizing the Full Chain
Java Application Code
↓ (Bytecode)
JVM (C++/C) → JIT Compiler → Machine Code
↓ (Native Methods, GC, Threading)
OS Libraries (glibc, MSVCRT) → System Calls → Kernel
Key Details to Clarify
Not All Paths Go Directly to System Calls:
- Many operations (e.g., arithmetic, object allocation) are handled purely in user space by the JVM/JIT.
- Only I/O, threading, memory management, etc., require system calls.
JNI and Native Libraries:
- Java applications can directly load native libraries (e.g., via
System.loadLibrary
) and call C/C++ code, bypassing the JVM’s internal layers. This adds another path:Java → JNI → Native Library (C/C++) → System Calls
- Java applications can directly load native libraries (e.g., via
AOT Compilation (Ahead-of-Time):
- Tools like GraalVM Native Image compile Java directly to native machine code ahead of time, skipping the JVM runtime. Here, the chain becomes:
Java → Native Code (via AOT) → System Calls
- Tools like GraalVM Native Image compile Java directly to native machine code ahead of time, skipping the JVM runtime. Here, the chain becomes:
OS Abstraction in the JVM:
- The JVM hides OS differences. For example, thread creation in Java uses
pthread_create()
on Linux/macOS butCreateThread()
on Windows, all abstracted by the JVM’s C++ code.
- The JVM hides OS differences. For example, thread creation in Java uses
Example: File I/O in Java
FileInputStream fis = new FileInputStream("file.txt");
int data = fis.read(); // Java → C++ → System Call → Kernel
- Java Layer:
FileInputStream.read()
(Java method). - JNI: Calls
JVM_Read()
(native method in JVM’s C++ code). - C++ Layer: Uses
read()
system call via OS-specific wrappers. - System Call: The kernel reads data from disk.
Summary
The full stack is:
Java (Bytecode/App)
→ JVM (C++/C)
→ OS Libraries → System Calls → Kernel
This abstraction allows Java to maintain write-once, run-anywhere portability while leveraging low-level system capabilities through the JVM’s native implementation.
References
Last updated on