Skip to content
Java getting started 7 min read

JDK, JRE & JVM

When you first install Java, you run into three confusing acronyms almost immediately: JVM, JRE, and JDK. They are three distinct — but nested — layers of the Java platform, and knowing which is which saves you a lot of confusion when setting up environments, writing build scripts, or explaining Java to a colleague.

Here is the short version before diving in:

TermFull NameWhat it does
JVMJava Virtual MachineExecutes compiled Java bytecode
JREJava Runtime EnvironmentJVM + standard libraries needed to run Java apps
JDKJava Development KitJRE + compiler, debugger, and tools needed to build Java apps

They nest like Russian dolls: JDK ⊇ JRE ⊇ JVM.

Note: Starting with Java 11, Oracle no longer ships a standalone JRE download. In practice you install the JDK everywhere — on development machines and servers alike. The JRE/JDK distinction still matters conceptually and in embedded/IoT contexts.

JDK JRE JVM nested architecture

The JVM — Java Virtual Machine

The JVM is the core engine of the Java platform. It is a software-based computer that reads Java bytecode (stored in .class files) and executes it on whatever hardware and operating system it is running on. This is how Java achieves its write once, run anywhere promise — the same .class file runs on Windows, macOS, Linux, and ARM processors without recompilation.

When you run a Java program, the JVM is responsible for:

  1. Loading — reading .class files from disk via the Class Loader subsystem.
  2. Verification — checking that the bytecode is valid and safe before execution.
  3. Execution — interpreting bytecode and, for hot code paths, compiling them to native machine code via the JIT compiler.
  4. Memory management — allocating objects on the heap and reclaiming them automatically through Garbage Collection.

The JVM is not tied to Java alone. Languages like Kotlin, Scala, Groovy, and Clojure all compile to JVM bytecode and run on it.

// After javac compiles HelloWorld.java → HelloWorld.class,
// the JVM loads and executes it:
//   java HelloWorld
//
// Internally the JVM calls this entry point:
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello from the JVM!");
    }
}

Output:

Hello from the JVM!

The JRE — Java Runtime Environment

The JRE bundles together everything a machine needs to run Java applications — but nothing more. It contains:

  • The JVM (the execution engine described above)
  • The Java Class Library — the full standard library (java.lang, java.util, java.io, java.net, and hundreds of other packages)
  • Supporting configuration files and resource files

If someone just needs to run your compiled JAR on a server, the JRE (or nowadays a full JDK) is what they install. They do not need javac or the other developer tools.

// The JRE provides all the standard library classes your code uses at runtime,
// for example java.util.ArrayList and java.lang.String:
import java.util.ArrayList;

public class JreDemo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("Java");
        list.add("is");
        list.add("portable");
        System.out.println(String.join(" ", list));
    }
}

Output:

Java is portable

Tip: The standard library bundled in the JRE is enormous. You rarely need to import anything from third-party libraries just to do string manipulation, file I/O, date/time handling, or basic networking — it is all there out of the box.

The JDK — Java Development Kit

The JDK is what you install as a developer. It includes everything in the JRE plus the tools you need to write and build Java programs:

ToolCommandPurpose
Java CompilerjavacCompiles .java source files to .class bytecode
Java LauncherjavaStarts the JVM and runs a program
ArchiverjarPackages .class files into a .jar archive
Documentation GeneratorjavadocGenerates HTML API docs from source comments
DisassemblerjavapInspects .class files (see javap Tool)
DebuggerjdbCommand-line debugger
Monitoring Toolsjconsole, jstack, jmapProfile and inspect running JVMs
// Compile with the JDK's javac:
//   javac Greeting.java
//
// Then run with the JVM:
//   java Greeting
public class Greeting {
    public static void main(String[] args) {
        String name = "Developer";
        System.out.printf("Welcome, %s! The JDK compiled this.%n", name);
    }
}

Output:

Welcome, Developer! The JDK compiled this.

The javac step is what turns your human-readable source into platform-neutral bytecode. That bytecode is then handed to the JVM for execution. For a deeper look at each step, see How a Java Program Runs.

How They Fit Together

A diagram is worth a thousand words here:

┌──────────────────────────────────────────────┐
│                    JDK                       │
│  javac  jar  javadoc  javap  jdb  jconsole   │
│  ┌────────────────────────────────────────┐  │
│  │                 JRE                   │  │
│  │   Java Class Library (rt.jar / mods)  │  │
│  │   ┌──────────────────────────────┐    │  │
│  │   │           JVM                │    │  │
│  │   │  Class Loader                │    │  │
│  │   │  Bytecode Verifier           │    │  │
│  │   │  Execution Engine (JIT)      │    │  │
│  │   │  Garbage Collector           │    │  │
│  │   └──────────────────────────────┘    │  │
│  └────────────────────────────────────────┘  │
└──────────────────────────────────────────────┘

Your workflow follows a simple path through these layers every time you work on a Java project:

  1. You write .java source files and use JDK tools (javac, jar) to compile and package them.
  2. At runtime, the JRE’s class library provides the standard APIs your code calls (ArrayList, String, System.out, etc.).
  3. The JVM underneath it all loads your bytecode, verifies it, JIT-compiles hot paths, manages heap memory, and handles threads.

Under the Hood

JVM Implementations

The JVM is a specification, not a single piece of software. Any implementation that passes the Java Compatibility Kit (JCK) tests is a valid JVM. Common ones include:

  • HotSpot (OpenJDK / Oracle) — the most widely used, ships with every standard JDK.
  • GraalVM — adds a polyglot runtime and an Ahead-of-Time (AOT) compiler that produces standalone native executables via native-image.
  • OpenJ9 (Eclipse) — originally IBM’s JVM, optimized for cloud deployments with a smaller memory footprint.
  • Azul Zing / Zulu — commercially supported distributions with low-latency GC options.

JVM Bytecode

When javac compiles your source, it produces bytecode — a set of roughly 200 instructions designed for a stack-based virtual machine, not your actual CPU. You can inspect these instructions yourself with javap -c:

// javap -c HelloWorld.class (abridged output):
public static void main(java.lang.String[]);
  Code:
     0: getstatic     #7  // Field java/lang/System.out
     3: ldc           #13 // String "Hello from the JVM!"
     5: invokevirtual #15 // Method java/io/PrintStream.println
     8: return

The JIT compiler watches which bytecode sequences are executed frequently (“hot spots”) and translates them to optimized native machine code on the fly — this is why a Java server application typically gets faster after it has been running for a few seconds as the JIT warms up.

JAVA_HOME and the PATH

When you install a JDK, you typically set two environment variables:

  • JAVA_HOME — points to the JDK root directory (e.g., /usr/lib/jvm/java-21-openjdk).
  • PATH — includes $JAVA_HOME/bin so your terminal can find java, javac, and the other tools.

Build tools like Maven and Gradle use JAVA_HOME to locate the JDK automatically. Step-by-step instructions are in Setting the PATH.

Which JDK Should You Install?

For most projects, grab the latest Java 21 LTS (Long-Term Support) build from Adoptium Temurin — it is free, open-source, and receives security patches until 2029.

# Verify your installation after setup:
java -version
javac -version

Output (example):

openjdk version "21.0.3" 2024-04-16
OpenJDK Runtime Environment Temurin-21.0.3+9 (build 21.0.3+9)
OpenJDK 64-Bit Server VM Temurin-21.0.3+9 (build 21.0.3+9, mixed mode)

javac 21.0.3

If java -version works but javac -version gives “command not found”, you have a JRE-only installation — download the full JDK instead.

Warning: Never rely on a system-wide JRE for development. Without javac and the other JDK tools, you cannot compile, package, or debug your own code.

Quick Reference

QuestionAnswer
I just want to run a .jar fileInstall the JDK (or a JRE if one is available)
I want to write and compile Java codeInstall the JDK
What executes my bytecode at runtime?The JVM
What provides java.util.ArrayList?The JRE class library
What provides javac?The JDK
Is the JVM the same on all platforms?No — there is a platform-specific JVM for Windows, macOS, Linux, etc. — but they all run the same bytecode

  • JVM Architecture — A deeper look at the class loader subsystem, runtime data areas, and the execution engine inside the JVM.
  • How a Java Program Runs — Follow a .java file step by step through compilation, class loading, and execution.
  • JIT Compilation & Bytecode — How HotSpot profiles your code and converts hot bytecode to optimized native machine code.
  • Garbage Collection Deep-Dive — How the JVM automatically manages heap memory and which collector to choose.
  • Setting the PATH — Configure JAVA_HOME and PATH on Windows, macOS, and Linux so all JDK tools are accessible.
  • Class Loaders & Class Loading — How the JVM’s bootstrap, platform, and application class loaders find and load .class files at runtime.
Last updated June 13, 2026
Was this helpful?