A deep-dive guide to understanding Java Development Kit, Java Runtime Environment, and Java Virtual Machine β covering JVM architecture, class loader, JIT compiler, garbage collector, heap & stack memory, and bytecode execution flow.
π
Last Updated
March 2026
β±οΈ
Read Time
22 min
π―
Level
Beginner to Intermediate
Overview β JDK, JRE, and JVM
One of the most frequently asked questions in every Java interview β and one of the most confused topics for beginners β is: "What is the difference between JDK, JRE, and JVM?" These three terms are at the heart of how Java works, and understanding them clearly will give you a solid foundation for everything else in Java.
In simple terms: JVM is the engine that runs your Java program. JRE is the environment that provides JVM + standard libraries to run it. JDK is the complete toolkit that includes JRE + developer tools to write, compile, and run Java programs. The relationship is: JDK β JRE β JVM.
Term
Full Form
One-Line Purpose
JVM
Java Virtual Machine
Executes Java bytecode on any platform
JRE
Java Runtime Environment
Provides the environment to RUN Java apps (JVM + Libraries)
JDK
Java Development Kit
Provides tools to WRITE, COMPILE, and RUN Java apps (JRE + Dev Tools)
Real-World Analogy β Kitchen, Restaurant & Chef
Before going deep into technical details, let us understand JDK, JRE, and JVM through a simple real-world analogy that makes these concepts unforgettable.
Java Component
Kitchen Analogy
Role
JVM
The Oven / Stove
The actual machine that does the cooking (execution). It runs the recipe (bytecode).
JRE
The Full Kitchen
Oven + all utensils, ingredients shelf, pantry. Everything needed to COOK (run) a dish.
JDK
Kitchen + Chef Tools
Full kitchen + chef's knife set, recipe book, measuring tools. Everything needed to CREATE + COOK dishes.
Bytecode (.class)
The Recipe
Platform-neutral instructions that any oven (JVM) can follow to produce the same dish.
Java Source (.java)
Raw Recipe Draft
The human-readable recipe written by the developer, before it is converted to standard format.
Key insight: A diner (end user) only needs the kitchen (JRE) to enjoy the food (run the app). Only the chef (developer) needs the full kitchen + chef tools (JDK) to create new dishes.
What is JVM β Java Virtual Machine?
The Java Virtual Machine (JVM) is an abstract computing machine β a software layer that acts as a virtual computer inside your real computer. It is the core reason Java is platform-independent. The JVM does not care whether the underlying hardware is Windows, Linux, or macOS β it provides a uniform execution environment for Java bytecode.
The JVM performs four primary responsibilities every time a Java program runs:
π₯
Load Code
The Class Loader reads .class bytecode files from disk, network, or memory and loads them into the JVM's Runtime Data Areas.
β
Verify Code
The Bytecode Verifier checks every loaded .class file for structural validity, type safety, and security violations β before a single instruction executes.
β‘
Execute Code
The Execution Engine (Interpreter + JIT Compiler) translates bytecode instructions into native machine code and runs them on the host CPU.
ποΈ
Manage Memory
The Garbage Collector automatically allocates memory for new objects on the Heap and reclaims memory from objects that are no longer reachable.
Important: The JVM itself is platform-specific β there is a different JVM implementation for Windows, Linux, and macOS. But the bytecode it executes is platform-neutral. This is the magic of WORA β the bytecode is universal, only the JVM varies.
β JavaJVM Demo β Runtime Properties
public class JVMInfo {
public static void main(String[] args) {
// JVM and Java version info
System.out.println("Java Version : " + System.getProperty("java.version"));
System.out.println("JVM Name : " + System.getProperty("java.vm.name"));
System.out.println("JVM Version : " + System.getProperty("java.vm.version"));
System.out.println("JVM Vendor : " + System.getProperty("java.vm.vendor"));
System.out.println("Java Home : " + System.getProperty("java.home"));
System.out.println("OS Name : " + System.getProperty("os.name"));
System.out.println("OS Arch : " + System.getProperty("os.arch"));
// Memory info
Runtime rt = Runtime.getRuntime();
System.out.println("Max Heap : " + (rt.maxMemory() / 1024 / 1024) + " MB");
System.out.println("Total Heap : " + (rt.totalMemory()/ 1024 / 1024) + " MB");
System.out.println("Free Heap : " + (rt.freeMemory() / 1024 / 1024) + " MB");
System.out.println("CPU Cores : " + rt.availableProcessors());
}
}
Output
Java Version : 21.0.2
JVM Name : OpenJDK 64-Bit Server VM
JVM Version : 21.0.2+13
JVM Vendor : Eclipse Adoptium
Java Home : /usr/lib/jvm/java-21-openjdk-amd64
OS Name : Linux
OS Arch : amd64
Max Heap : 3924 MB
Total Heap : 256 MB
Free Heap : 244 MB
CPU Cores : 8
JVM Architecture β Deep Dive
The JVM is not a single monolithic program β it is a carefully designed system of three interconnected subsystems. Understanding this architecture is crucial for writing performant Java code and for cracking advanced Java interviews.
Connects JVM to native C/C++ librariesUsed by java.io, java.net, javax.crypto
Native Method Libraries
OS-level libraries (.dll on Windows, .so on Linux)Hardware-level operations
Architecture Diagram
Class Loader Subsystem β How Java Loads Classes
The Class Loader Subsystem is the first stage of JVM execution. When your Java program starts, the JVM does not load all classes at once β it uses lazy loading, loading classes only when they are first needed. The Class Loader performs three phases:
Phase
What Happens
Example
1. Loading
Reads the .class file binary from source (disk, network, JAR) and creates a Class object in Method Area memory.
HelloWorld.class is read from disk into JVM memory
2. Linking
Three sub-steps: Verification (bytecode validity check) β Preparation (static variables allocated with default values) β Resolution (symbolic references replaced with direct memory references).
static int count gets default value 0 in memory
3. Initialization
Static initializers and static variable assignments execute in top-to-bottom order. This is when static blocks run.
Loads YOUR application classes and third-party library classes (from Maven/Gradle)
Delegation Model: When a class needs to be loaded, the Application ClassLoader first delegates to the Extension ClassLoader, which delegates to the Bootstrap ClassLoader. Only if the parent cannot find the class does the child attempt to load it. This prevents malicious code from replacing core Java classes like java.lang.String.
String ClassLoader : null
This class ClassLoader : jdk.internal.loader.ClassLoaders$AppClassLoader@251a69d7
Parent ClassLoader : jdk.internal.loader.ClassLoaders$PlatformClassLoader@1b6d3586
Grandparent CLoader : null
Runtime Data Areas β JVM Memory Model
The JVM divides memory into five distinct Runtime Data Areas. Understanding which data lives where is essential for writing memory-efficient Java programs and diagnosing OutOfMemoryError and StackOverflowError issues.
ποΈ
Method Area (Metaspace)
Shared across all threads. Stores class-level data: class name, parent class, method bytecode, static variables, constant pool. In Java 8+, this is called Metaspace and is in native memory (not JVM heap). StackOverflow in Metaspace is possible if too many classes are loaded dynamically.
π¦
Heap Area
Shared across all threads. This is where ALL objects and arrays are allocated (created with 'new'). Divided into Young Generation (Eden + Survivor spaces) and Old Generation. Managed by the Garbage Collector. OutOfMemoryError: Java heap space occurs when Heap is full.
π
Stack Area (JVM Stack)
One Stack per thread. Stores method call frames β each frame contains: local variables, operand stack, and reference to constant pool. LIFO structure β frames are pushed on method call and popped on method return. StackOverflowError occurs with infinite recursion.
π’
PC Register (Program Counter)
One PC Register per thread. Stores the address of the currently executing bytecode instruction. When a thread switches between methods, the PC Register saves the return address so execution can resume correctly.
π
Native Method Stack
One per thread. Used when Java code calls native methods (C/C++ code via JNI). Similar to JVM Stack but for native code execution. Used internally by java.io for file I/O and java.net for networking.
Heap Memory β Young & Old Generation
Heap Region
Sub-Region
Description
GC Type
Young Generation
Eden Space
All new objects are first created here.
Minor GC (fast)
Young Generation
Survivor 0 (S0)
Objects that survived one GC cycle move here from Eden.
Minor GC (fast)
Young Generation
Survivor 1 (S1)
Objects alternate between S0 and S1 across GC cycles.
Minor GC (fast)
Old Generation
Tenured Space
Long-lived objects (survived multiple GC cycles) are promoted here.
Major GC (slow)
Non-Heap
Metaspace
Class metadata, static variables, constant pool. Replaced PermGen in Java 8.
GC on class unload
β JavaHeap vs Stack β Memory Demo
public class MemoryDemo {
// Instance variable β stored in HEAP (part of the object)
int instanceVar = 100;
public static void main(String[] args) {
// Local primitive β stored in STACK
int localVar = 50;
// Object reference 'obj' β stored in STACK
// Actual MemoryDemo object β stored in HEAP
MemoryDemo obj = new MemoryDemo();
// String literal β stored in String Pool (part of Heap)
String name = "Java";
// 'new' String β always creates a new object in Heap
String name2 = new String("Java");
System.out.println("localVar : " + localVar); // Stack
System.out.println("instanceVar: " + obj.instanceVar); // Heap
System.out.println("name == name2: " + (name == name2)); // false (different objects)
System.out.println("name.equals: " + name.equals(name2));// true (same content)
}
}
The Execution Engine is the heart of the JVM β it is responsible for actually running your Java bytecode. It has two strategies for executing bytecode, and understanding both explains why Java's performance has improved dramatically over the years.
Component
Strategy
Speed
When Used
Characteristic
Interpreter
Reads and executes bytecode one instruction at a time
Slow (starts fast)
All code initially
Simple, no optimization, immediate startup
JIT Compiler
Compiles frequently-used bytecode to native machine code
Very Fast
Hot code (called many times)
Slower startup but faster sustained execution
C1 Compiler
Light optimization JIT (client compiler)
Medium
Early hot detection
Faster compilation, moderate optimization
C2 Compiler
Aggressive optimization JIT (server compiler)
Fastest
Heavily repeated code
Slower compilation, maximum performance
GraalVM JIT
Next-gen JIT written in Java itself (Java 21+)
Excellent
Modern enterprise workloads
Better optimizations, supports native image
How JIT Works: The JVM starts by interpreting all bytecode. It counts how many times each method is called. When a method crosses the invocation threshold (default: 10,000 times), the JIT compiler compiles it to native machine code. Future calls execute the native code directly β bypassing the interpreter entirely. This is why Java applications get faster over time the longer they run.
β JavaJIT Effect β Performance Demo
public class JITDemo {
public static void main(String[] args) {
// First run β JVM interprets bytecode (slower)
long start1 = System.nanoTime();
long result1 = computeSum(1_000_000);
long time1 = System.nanoTime() - start1;
// Second run β JIT has compiled computeSum to native code (faster)
long start2 = System.nanoTime();
long result2 = computeSum(1_000_000);
long time2 = System.nanoTime() - start2;
System.out.println("Result 1 : " + result1);
System.out.println("Time 1 : " + time1 / 1_000_000 + " ms (interpreted)");
System.out.println("Result 2 : " + result2);
System.out.println("Time 2 : " + time2 / 1_000_000 + " ms (JIT compiled)");
}
static long computeSum(int n) {
long sum = 0;
for (int i = 1; i <= n; i++) sum += i;
return sum;
}
}
Output
Result 1 : 500000500000
Time 1 : 12 ms (interpreted)
Result 2 : 500000500000
Time 2 : 1 ms (JIT compiled)
Garbage Collector β Automatic Memory Management
Java's Garbage Collector (GC) is one of its most celebrated features. Unlike C and C++ where developers manually allocate and free memory (malloc/free), Java's GC automatically identifies and reclaims memory occupied by objects that are no longer reachable from any live thread. This prevents the two most common memory bugs: memory leaks (forgetting to free) and dangling pointers (freeing and then using).
How Garbage Collection Works β Mark & Sweep
βΆ
Phase 1 β Mark: The GC starts from GC Roots (active thread stacks, static variables, JNI references) and marks every reachable object in the Heap by traversing all references.
βΆ
Phase 2 β Sweep: All objects NOT marked as reachable are considered garbage. The GC reclaims their memory.
βΆ
Phase 3 β Compact (optional): Some GC algorithms compact live objects together to eliminate fragmentation, making future allocations faster.
GC Algorithm
Introduced
Best For
Stop-the-World?
Java 21 Default?
Serial GC
Java 1
Single-threaded / small apps
Yes (long pause)
β No
Parallel GC
Java 5
Throughput-focused batch processing
Yes (shorter pauses)
β No
G1GC
Java 7
General-purpose β balanced latency/throughput
Minimal pauses
β Yes (Default)
ZGC
Java 11
Ultra-low latency (sub-millisecond pauses)
Mostly concurrent
β Available
Shenandoah GC
Java 12
Low-latency, large heaps
Mostly concurrent
β Available
Epsilon GC
Java 11
Performance testing (no GC β intentional)
N/A
β Dev/Test only
β JavaGC Demo β Eligible for Collection
public class GCDemo {
String name;
GCDemo(String name) {
this.name = name;
System.out.println("Created: " + name);
}
@Override
protected void finalize() {
// Called by GC before reclaiming memory (deprecated in Java 9+)
System.out.println("GC collected: " + name);
}
public static void main(String[] args) throws Exception {
GCDemo obj1 = new GCDemo("Object-A"); // obj1 β Heap
GCDemo obj2 = new GCDemo("Object-B"); // obj2 β Heap
obj1 = null; // Object-A is now unreachable β eligible for GC
obj2 = null; // Object-B is now unreachable β eligible for GC
System.gc(); // Request GC (JVM may or may not run it immediately)
Thread.sleep(1000);
System.out.println("Main method ends.");
}
}
The Java Runtime Environment (JRE) is the minimum software package required to run a pre-compiled Java application. It is a superset of the JVM β meaning it contains the JVM plus the standard Java class libraries that Java programs depend on.
JRE Component
Description
JVM
The Java Virtual Machine β executes bytecode
java.lang package
Core language classes: Object, String, Math, System, Thread, Exception
java.util package
Collections, Date, Scanner, Random, Optional
java.io package
File I/O, Streams, Readers, Writers
java.net package
Networking: Socket, URL, HttpURLConnection
java.util.concurrent
Thread pools, locks, atomic variables
java.sql package
JDBC API for database connectivity
javax.* packages
Extended APIs: crypto, XML, net, naming
rt.jar / modules
Pre-compiled bytecode of all standard library classes
Who needs JRE? End users who want to run a Java application (like a JAR file) but do not intend to develop Java programs. However, since Java 9 the standalone JRE is no longer distributed β you install the JDK instead, or create a custom minimal runtime using jlink.
What is JDK β Java Development Kit?
The Java Development Kit (JDK) is the complete toolkit for Java development. It is a superset of the JRE β it contains everything in the JRE plus a set of command-line developer tools. If you are a Java developer, you always install the JDK. As of Java 9, Oracle no longer ships a separate JRE β only the JDK.
The JDK is available from multiple vendors, all based on the same OpenJDK source code:
βΆ
Eclipse Temurin (Adoptium): Most popular free OpenJDK build. Recommended for most developers.
βΆ
Oracle JDK 21: Free under NFTC license. Same codebase as OpenJDK with Oracle-specific monitoring tools.
βΆ
Amazon Corretto: Free OpenJDK with long-term AWS support. Best for AWS deployments.
βΆ
Microsoft OpenJDK: Free, optimized for Azure and Windows environments.
The JDK includes a rich set of command-line tools in its bin/ directory. Every Java developer should know these tools β especially javac, java, javap, jdb, and jar.
Tool
Command
Purpose
Example Usage
Java Compiler
javac
Compiles .java source files to .class bytecode
javac HelloWorld.java
Java Launcher
java
Starts JVM and runs a compiled .class / .jar file
java HelloWorld | java -jar app.jar
Java Disassembler
javap
Disassembles .class files β shows bytecode or method signatures
javap -c HelloWorld.class
Java Debugger
jdb
Command-line debugger for Java programs
jdb HelloWorld
Javadoc Generator
javadoc
Generates HTML API documentation from /** */ comments
javadoc -d docs HelloWorld.java
JAR Tool
jar
Creates, lists, and extracts JAR archive files
jar cf app.jar *.class
JVM Monitor
jconsole
GUI tool to monitor JVM memory, threads, and GC
jconsole (connects to running JVM)
Flight Recorder
jfr
Records JVM performance data for analysis
jfr print recording.jfr
Module Tool
jmod
Creates .jmod files for Java 9+ module system
jmod create --class-path mods/ mymod.jmod
Runtime Image
jlink
Creates custom minimal JRE images for distribution
jlink --add-modules java.base --output myruntime
Native Image
jpackage
Packages Java apps as native installers (.exe, .dmg)
Manages cryptographic keys and certificates (SSL/TLS)
keytool -genkeypair -alias mykey
javap β Inspect Bytecode Like a Pro
π» Terminaljavap β View Bytecode Instructions
# Compile the class first:
javac HelloWorld.java
# View method signatures (no bytecode):
javap HelloWorld
# View full bytecode disassembly:
javap -c HelloWorld
# View detailed bytecode + constant pool:
javap -verbose HelloWorld
Output
Compiled from "HelloWorld.java"
public class HelloWorld {
public HelloWorld();
public static void main(java.lang.String[]);
}
// javap -c output (bytecode):
public static void main(java.lang.String[]);
Code:
0: getstatic #7 // Field java/lang/System.out
3: ldc #13 // String Hello, World!
5: invokevirtual #15 // Method println:(String)V
8: return
JDK β JRE β JVM β Architecture Diagram
The diagram below shows the nested relationship between JDK, JRE, and JVM β from the outermost developer toolkit down to the innermost execution engine.
Class Loader SubsystemMethod Area (Metaspace)Heap (Young + Old Generation)JVM Stack (per thread)PC Register (per thread)InterpreterJIT Compiler (C1 + C2)Garbage Collector (G1GC / ZGC)
Architecture Diagram
JDK vs JRE vs JVM β Master Comparison Table
This is the definitive comparison table for JDK, JRE, and JVM β covering every angle that can be asked in interviews.
Parameter
JVM
JRE
JDK
Full Name
Java Virtual Machine
Java Runtime Environment
Java Development Kit
Primary Purpose
Executes Java bytecode
Provides runtime to run Java apps
Provides tools to develop & run Java
Contains
Interpreter, JIT, GC, Memory Mgr
JVM + Java Class Libraries
JRE + javac, javap, jdb, javadoc, jar...
Includes JVM?
β It IS the JVM
β Yes
β Yes
Includes javac?
β No
β No
β Yes
Includes Libraries?
β No (only executes)
β Yes (java.lang, java.util...)
β Yes (same as JRE)
Platform Specific?
β Yes (different per OS)
β Yes (bundles OS-specific JVM)
β Yes (different per OS)
Who Needs It?
Runtime engine (internal)
End users running Java apps
Developers writing Java apps
File Size
Smallest (~40 MB)
Medium (~200 MB)
Largest (~300-400 MB)
Can Compile Code?
β No
β No
β Yes (javac compiler)
Can Run Code?
β Yes (its only job)
β Yes
β Yes
Shipped Separately?
No (part of JRE)
Merged into JDK since Java 9
β Yes β download from adoptium.net
Current Version 2026
21.0.x
Part of JDK 21
JDK 21 LTS (recommended)
End-to-End Bytecode Execution Flow
Let us trace the complete journey of a Java program β from the moment you type source code to the moment output appears on screen. Every step maps to a specific JVM component.
These are the most commonly asked interview questions on JDK, JRE, JVM, and Java memory model β from fresher to mid-level positions.
JVM (Java Virtual Machine) is the execution engine that runs Java bytecode and provides platform independence. JRE (Java Runtime Environment) = JVM + Java Class Libraries β the minimum needed to run a compiled Java application. JDK (Java Development Kit) = JRE + Developer Tools (javac, javap, jdb, javadoc, jar) β required to write, compile, debug, and run Java programs. The nesting relationship is: JDK β JRE β JVM.
JVM architecture has three main subsystems: (1) Class Loader Subsystem β loads, links (verifies, prepares, resolves), and initializes .class files. (2) Runtime Data Areas β JVM memory: Method Area (class metadata), Heap (objects), JVM Stack (method frames), PC Register (current instruction), Native Method Stack. (3) Execution Engine β Interpreter (line-by-line execution), JIT Compiler (hot code to native), Garbage Collector (memory reclamation). Plus Native Method Interface (JNI) to call native C/C++ code.
Stack is thread-private, LIFO-structured, stores method frames and local variables. It is fast, small (~256KB-1MB), auto-managed. Overflow β StackOverflowError. Heap is shared across threads, stores all objects created with 'new', managed by GC, larger (~256MB-4GB). Overflow β OutOfMemoryError. Key rule: local primitives β Stack; objects and arrays β Heap; object references β Stack (the reference) pointing to Heap (the object).
JIT (Just-In-Time) Compiler is part of the JVM Execution Engine. Initially, all bytecode is interpreted line-by-line (slow). The JIT monitors execution and identifies 'hot' code β methods called more than ~10,000 times. It compiles these hot methods directly to native machine code. Future calls bypass the interpreter and execute the native code directly. This is why Java apps get faster over time β the longer they run, the more code gets JIT-compiled to near-native speed.
Loading: reads the .class binary and creates a Class object in Method Area. Linking: has three sub-phases β Verification (bytecode structure and type safety), Preparation (static variables allocated with default values: intβ0, booleanβfalse, Objectβnull), Resolution (symbolic references like class names replaced with direct memory addresses). Initialization: static initializer blocks and static variable assignments execute top-to-bottom. This is when your static { } blocks run.
This is a classic trick question. The JVM itself is NOT platform-independent β there is a different JVM implementation for Windows (jvm.dll), Linux (libjvm.so), and macOS (libjvm.dylib). What is platform-independent is Java BYTECODE (.class files). The bytecode specification is the same everywhere. Each OS has its own JVM that knows how to execute that universal bytecode for that specific OS. So Java achieves platform independence not because JVM is universal, but because BYTECODE is universal and each JVM translates it to local native code.
Garbage Collection (GC) is automatic memory management β the JVM identifies objects in the Heap with no live references and reclaims their memory. Process: Mark (find all reachable objects from GC roots) β Sweep (reclaim unreachable objects) β Compact (optional, defragment). Java 21 GC algorithms: G1GC (default β balanced latency/throughput), ZGC (ultra-low latency, sub-millisecond pauses, Java 21 is production-ready), Shenandoah (low-latency, large heaps), Serial GC (single-threaded, embedded), Parallel GC (throughput-focused), Epsilon GC (no GC β for testing).
javac is the Java Compiler (part of JDK only, not JRE). It takes .java source files as input and produces .class bytecode files: javac HelloWorld.java β HelloWorld.class. java is the Java Launcher (part of JRE and JDK). It starts the JVM and runs a compiled class: java HelloWorld runs the main() method in HelloWorld.class. You need JDK for javac; you only need JRE for java. Since Java 11, you can use java HelloWorld.java to compile-and-run in one step (source-code launcher).
StackOverflowError: occurs when the JVM Stack runs out of space. Most common cause: infinite recursion β a method calls itself endlessly, creating infinite stack frames. Each frame is ~few KB; the stack is only ~256KB-1MB. OutOfMemoryError: Java heap space: occurs when the Heap is full and GC cannot free enough memory. Usually caused by: creating objects faster than GC can collect them, memory leaks (objects referenced but unused), or loading extremely large data sets. Fix: increase heap (-Xmx4g) or fix the leak.
Step-by-step: (1) OS launches the JVM process. (2) JVM initializes Runtime Data Areas (Heap, Method Area, etc.). (3) Bootstrap ClassLoader loads core Java classes (java.lang.Object, etc.). (4) Application ClassLoader loads HelloWorld.class from the classpath. (5) Bytecode Verifier checks HelloWorld.class for validity. (6) JVM looks for public static void main(String[] args) in HelloWorld. (7) Execution Engine starts interpreting the main() bytecode. (8) JIT compiles hot sections. (9) System.out.println() executes β output appears. (10) main() returns, JVM initiates shutdown, GC runs final cleanup.
Practice Questions β Test Your Knowledge
Test your understanding of JDK, JRE, and JVM concepts. Try answering each question before revealing the answer.
1. A user wants to run a pre-compiled Java .jar application but does not want to develop Java programs. What is the minimum they need to install?
Easy
β AnswerTechnically JRE (Java Runtime Environment) β it contains JVM + Class Libraries, which is all that is needed to run a compiled Java application. However, since Java 9, Oracle no longer ships a standalone JRE. In practice, users install the full JDK 21, which includes the JRE. Alternatively, developers can create a minimal custom runtime using jlink that includes only the modules the application needs.
2. Why does the JVM return 'null' when you call String.class.getClassLoader()?
Medium
β AnswerBecause String is loaded by the Bootstrap ClassLoader, which is implemented in native C++ code (not Java). In Java, when a ClassLoader is implemented natively, it is represented as null in the Java API. So String.class.getClassLoader() returning null is correct behavior β it means the Bootstrap ClassLoader loaded it, not the Application or Platform ClassLoader.
3. What is the difference between Minor GC and Major GC?
Medium
β AnswerMinor GC (Young Generation GC): runs when Eden space fills up. It is fast (milliseconds) because it only scans the small Young Generation. Objects that survive are moved to Survivor spaces. Major GC (Old Generation / Full GC): runs when Old Generation fills up. Slower (seconds) because it scans the entire Heap. Can cause 'stop-the-world' pauses where all application threads halt. Frequent Major GCs indicate a memory leak or undersized heap.
4. Java is called 'interpreted' by some and 'compiled' by others. Who is right?
Medium
β AnswerBoth are partially right β Java is a hybrid. It is first compiled (javac compiles .java to .class bytecode β this is compilation). Then the JVM interprets bytecode initially. The JIT compiler then further compiles hot bytecode to native machine code at runtime. So Java involves: ahead-of-time compilation (javac), interpretation (JVM Interpreter), and just-in-time compilation (JIT). This makes it neither purely interpreted (like Python) nor purely compiled (like C++).
5. If you create 100 threads in a Java application, how many JVM Stacks are there?
Medium
β Answer100 JVM Stacks β one per thread. Each thread gets its own private JVM Stack (and its own PC Register and Native Method Stack). The Heap and Method Area (Metaspace) are shared across all 100 threads. This is why multi-threaded Java applications can have issues with Heap data (race conditions, synchronization needed) but not with Stack data (each thread's local variables are completely private).
6. What is the String Pool and which JVM memory area does it belong to?
Hard
β AnswerThe String Pool (also called String Intern Pool) is a special cache in the Heap that stores unique String literals. When you write String s = "Java", the JVM checks the pool β if "Java" already exists, it returns the same reference. New String instances with identical content share the same pool entry, saving memory. Since Java 7, the String Pool is in the main Heap (was in PermGen/Method Area before Java 7). String s1 = "Java" and String s2 = "Java" point to the SAME pool object. String s3 = new String("Java") creates a new Heap object outside the pool.
7. What is 'stop-the-world' in Java GC? Why is it a problem?
Hard
β AnswerA 'stop-the-world' (STW) pause is when the JVM pauses ALL application threads to perform GC work. During this pause, no user requests are processed, no code executes β the application appears frozen. STW pauses are a problem for latency-sensitive applications: a 500ms GC pause in a financial trading system or web server can cause transaction failures or timeout errors. Modern GC algorithms (ZGC, Shenandoah) minimize STW pauses to under 1ms by doing most GC work concurrently with the application threads.
8. What does the -Xmx and -Xms JVM flag do? Give a practical example.
Hard
β Answer-Xms sets the INITIAL heap size (allocated at JVM startup). -Xmx sets the MAXIMUM heap size (JVM will never exceed this). Example: java -Xms256m -Xmx2g MyApp β starts with 256MB heap, can grow up to 2GB. Best practice: set -Xms equal to -Xmx for server applications to avoid dynamic heap resizing overhead (java -Xms2g -Xmx2g MyApp). Too small -Xmx β OutOfMemoryError. Too large -Xmx β wastes RAM and GC takes longer. Choose based on profiling your application's actual memory usage.
Conclusion β JDK vs JRE vs JVM Summary
You now have a thorough understanding of the three pillars of the Java platform. Let us consolidate everything with a final cheat-sheet summary:
What You Learned
Key Takeaway
JVM
Execution engine β loads, verifies, and runs bytecode. Platform-specific but executes platform-neutral bytecode.
JRE
JVM + Class Libraries. Minimum needed to RUN a Java app. No compiler included.
JDK
JRE + Dev Tools (javac, jdb, javadoc, jar...). Required to DEVELOP Java apps. Always install JDK.
Stack: thread-private, LIFO, local vars β StackOverflowError. Heap: shared, objects β OutOfMemoryError.
Bytecode
Platform-neutral intermediate format. Compiled once by javac, runs everywhere via any JVM.
WORA
JVM is platform-specific; bytecode is platform-neutral. JVM bridges the gap on every OS.
With this understanding of Java's internals, you are now ready to move forward with confidence. The next chapter covers Java Syntax β variables, operators, control flow, and the rules that govern every line of Java code you write. β
Frequently Asked Questions (FAQ) β JDK vs JRE vs JVM
JVM (Java Virtual Machine) is the engine that executes Java bytecode and provides platform independence. JRE (Java Runtime Environment) = JVM + Java Class Libraries β the minimum needed to RUN a compiled Java application. JDK (Java Development Kit) = JRE + Developer Tools (javac, jdb, javadoc, jar) β required to WRITE, COMPILE, and RUN Java programs. Nesting: JDK β JRE β JVM.
JVM architecture has three main subsystems: (1) Class Loader Subsystem β loads, links (verify, prepare, resolve), and initializes .class files. (2) Runtime Data Areas β JVM memory: Method Area, Heap, JVM Stack, PC Register, Native Method Stack. (3) Execution Engine β Interpreter, JIT Compiler, Garbage Collector. It also has the Native Method Interface (JNI) for calling native C/C++ code.
The JIT Compiler is part of the JVM Execution Engine. It monitors bytecode execution and identifies frequently called methods ('hot spots'). When a method is called more than ~10,000 times, JIT compiles it to native machine code. Future calls execute the native code directly β making Java applications significantly faster over time compared to pure interpretation.
Stack is thread-private, LIFO-structured, stores local variables and method frames. It is fast, small, and automatically cleared when methods return. Full Stack β StackOverflowError. Heap is shared across all threads and stores all objects created with 'new'. Managed by the Garbage Collector. Full Heap β OutOfMemoryError. Primitive local variables go to Stack; objects always go to Heap.
The Java Garbage Collector (GC) automatically manages Heap memory β it identifies objects with no live references and reclaims their memory. Process: Mark (find reachable objects) β Sweep (reclaim unreachable objects) β Compact (optional defragmentation). Java 21 includes G1GC (default), ZGC (sub-millisecond pauses), Shenandoah, Parallel, and Serial GC. GC eliminates manual memory management and prevents memory leaks.