JDK, JRE, and JVM: Understanding the Java Platform Components and How They Work Together

Kishan Kumar
8 min readOct 28, 2023

--

If you’re a Java developer, you’ve likely encountered the trio of “J”s — JVM, JRE, and JDK. While it’s tempting to gloss over these terms and focus on coding, having a grasp of these fundamentals can save you from potential pitfalls and embarrassment when working with the language.

In this article, we’ll explore the significance of these “J”s and unravel their meanings. But first, let’s start by decoding their full forms:

  • JVM: Java Virtual Machine
  • JRE: Java Runtime Environment
  • JDK: Java Development Kit

JVM: Java Virtual Machine

The JVM stands as the cornerstone of the Java language. It’s the place where your Java programs come to life. To illustrate its role, let’s craft a straightforward Java program and delve into how these components interconnect.

Open your text editor and enter the following simple “Hello World” message, then save it as HelloWorld.java:

public class HelloWorld{
public static void main(String[] args) {
System.out.println("Hello World!");
}
}

As you may know, our computers don’t comprehend English or any human language for that matter; they speak the language of 0s and 1s. To bridge this gap, we need to convert our program into a format that the computer can understand.

This transformation process is known as compilation, and it’s handled by the javac, also known as the Java Compiler. To compile the program, execute the following command:

javac HelloWorld.java

After running this command, you’ll find a new file generated — HelloWorld.class.

If you’d like to inspect the contents of the .class file, you can use online tools like hexed.it or iamkate.com/code/binary-file-viewer.

It's a bunch of garbage to you but not to the computer.

Now, let's try to run it. To run it, type the following command:

$ java HelloWorld

Output:

Hello World

The entire process can be broken down into three fundamental steps:

  1. Writing and Saving the Java Program: First, you need to create a Java program by adhering to Java syntax rules and save it with the file name HelloWorld.java. This can be accomplished using a text editor or an Integrated Development Environment (IDE) like IntelliJ IDEA.
  2. Compiling into Bytecode: In the second step, you compile the Java program into bytecode using the javac command. Bytecode is a platform-independent representation of your program, suitable for execution by the Java Virtual Machine (JVM).
  3. Running the Program with the JVM: The third step involves running the program by invoking the JVM using the java command. It's at this point that the JVM comes into play.

What Are Bytecodes?

Bytecode is an intermediate code generated by a compiler after compiling the source code. It’s not specific to any physical machine and comprises binary, hexadecimal, and macro instructions (e.g., new, add, swap, etc.). However, the CPU doesn’t directly understand bytecode. To bridge this gap, an interpreter is required to convert Java bytecode into machine code.

Flowchart of the Process. Image by Kishan Kumar

The key idea here is that there are codes understood only by specific machines. For instance, adding two numbers, such as 3 and 5, would involve different operations on different machines. Here are hypothetical examples of machine code for x86 and ARM architectures:

x86 machine code: 90 24 40 00 12

ARM machine code: 01 00 A0 E3

Note: These are random numbers used for illustration.

The interpreter’s role is to translate bytecode, which is independent of the machine, into machine code, which is machine-dependent.

JVM is tasked with the important responsibility of translating Java bytecode into machine-specific instructions that the underlying hardware can comprehend and execute. It is this feature of the JVM that provides platform independence, allowing Java programs to run on any device or operating system with a compatible JVM implementation.

The JVM comprises various components that store critical data information for the Java program, including:

  1. Class Area: This stores per-class structures, such as the runtime constant pool, field, and method data, and code for methods.
  2. Heap: It is responsible for storing objects created by the Java program at runtime.
  3. Stack: The stack stores local variables and partial results of each thread executing in the Java program.
  4. Program Counter (PC) Register: This stores the address of the next instruction to be executed by each thread in the Java program.

It’s important to note that the JVM is not a monolithic entity implemented by a single vendor. There are various JVM implementations for different platforms, such as the Oracle HotSpot JVM, OpenJDK, and more. While each implementation may have unique features and optimizations, they must adhere to the JVM specification and pass a compatibility test suite known as the Java Compatibility Kit (JCK).

What Happens When You Run java HelloWorld

When you execute java HelloWorld, the JVM performs several crucial tasks:

  1. Loading Java ByteCode: It loads the Java ByteCode of the HelloWorld program (the .class file).
  2. Verifying Bytecode: The JVM verifies the validity and security of the bytecode using a subsystem called the Bytecode verifier.
  3. Linking with Java API and Libraries: The bytecode is linked with the Java API and other libraries using a subsystem known as the Linker.
  4. Interpreting Bytecode: It interprets the bytecode and executes it as native instructions understood by the CPU, thanks to a subsystem called the Interpreter.
  5. Optional Compilation to Native Code: Some parts of the bytecode may be optionally compiled into native code for improved performance using a subsystem known as the Just-in-Time (JIT) compiler.
  6. Managing Memory: The JVM handles memory allocation and deallocation for Java objects using a subsystem called the Garbage Collector.
Image taken from https://www.geeksforgeeks.org/

JRE: Java Runtime Environment

The Java Runtime Environment (JRE) comprises a collection of software tools and libraries that enable Java applications to operate on various computer systems and devices. Think of it as an operating system of sorts, facilitating coordination among different hardware components, with one of the most pivotal components being the Java Virtual Machine (JVM).

Components of JRE:

  1. JVM: Yes, the JVM is an integral part of the JRE and stands as one of its most critical components.
  2. Java Class Libraries: Within the JRE, you’ll find an array of standard class libraries and APIs, providing extensive functionality to Java applications. These libraries encompass data structures like lists, maps, heaps, input/output operations, networking, graphics, and more.
  3. Executable Binaries: The JRE also houses executable binaries and tools, such as the java command, which was discussed earlier. The java command is employed to run programs within the JVM.
  4. Supporting Files and JARs: The JRE includes various supporting files and Java Archive (JAR) files, which are crucial for the execution of Java applications.

How it Works:

  • When you execute a Java application, you typically use the java command followed by the name of the class containing the main method (the entry point of your application). For instance: java HelloWorld.
  • The java command initiates the JVM, which operates within the JRE.
  • The JVM loads the class files and executes the main method. It accomplishes this by interpreting the bytecode or, in some cases, by Just-In-Time (JIT) compiling it into native machine code for enhanced performance.
  • The JVM utilizes the Java Class Libraries to access various system resources and fulfill the tasks as instructed by the Java application.

In summary, the Java Runtime Environment (JRE) plays a vital role in the Java platform, allowing Java applications to run on a diverse array of devices and operating systems. It encompasses the Java Virtual Machine (JVM) and a collection of class libraries, enabling Java programs to execute in a platform-independent manner.

JDK: Java Development Kit

The Java Development Kit (JDK) serves as a comprehensive software development package that equips developers with the tools and libraries necessary for building Java applications.

The JDK encompasses the following essential components:

  • JRE (Java Runtime Environment): This constitutes the runtime environment for Java applications and applets. It includes the JVM, responsible for executing Java bytecode, and the core class libraries that provide the fundamental features of the Java language.
  • Java Compiler (javac): The Java compiler converts Java source code into Java bytecode, which serves as the intermediary representation of the Java program, capable of being executed by the JVM. The compiler also conducts checks and optimizations on the source code to ensure correctness and efficiency.
  • Java Debugger (jdb): This tool assists in the identification and resolution of errors in your Java program. It allows developers to set breakpoints, inspect variables, execute commands, and take control of the program’s execution flow.
  • Java Documentation Generator (javadoc): Javadoc generates HTML documentation from comments within your Java source code. It is an invaluable tool for documenting your program and its API, aiding both developers and yourself.
  • Java Archiver (jar): The Java Archiver packages Java classes and resources into a single file, known as a JAR (Java Archive) file. This facilitates the distribution and deployment of your Java application or library.
  • Other Tools: The JDK provides an assortment of other tools useful for developing and testing Java applications, including appletviewer, keytool, policytool, jconsole, jvisualvm, and more.

The JDK is an essential kit for Java developers, enabling them to create, compile, debug, document, and package Java applications effectively. It is a versatile toolkit that forms the backbone of Java software development.

Conclusion:

In the world of Java development, understanding the roles of the three “J”s — JVM, JRE, and JDK — is more than a matter of convenience; it’s a fundamental necessity. These components form the bedrock of the Java platform and are crucial for both developers and end-users.

The Java Virtual Machine (JVM) serves as the heart of the Java language, executing Java programs by translating bytecode into machine-specific instructions. It provides the foundation for Java’s platform independence and facilitates its “write once, run anywhere” promise.

The Java Runtime Environment (JRE) complements the JVM by providing the necessary runtime environment for Java applications to run seamlessly. It houses not only the JVM but also a comprehensive set of class libraries and tools, creating a robust environment for Java programs.

On the developer’s side, the Java Development Kit (JDK) empowers the creation of Java applications. It includes the JRE, the indispensable Java compiler (javac), a debugger (jdb), and other essential tools for building, testing, and documenting Java software.

In essence, the JVM, JRE, and JDK work in harmony to make Java a versatile and powerful programming language. The JVM takes Java bytecode and translates it into machine-specific instructions, while the JRE provides the runtime environment for these applications. Meanwhile, the JDK equips developers with the necessary tools and libraries to create, test, and deploy Java applications effectively.

Whether you’re a seasoned Java developer or just starting on your programming journey, grasping the significance of these “J”s is a fundamental step toward becoming a proficient Java practitioner. With this knowledge, you’ll not only write better Java code but also appreciate the magic that happens behind the scenes when you run a Java application.

Thanks a lot for reading such a long article. To show your support, please visit my website: https://www.0xkishan.com/

--

--

Kishan Kumar

Building PhonePe. Dive into insightful articles on decentralized systems, Tech and AI trends