Java Architecture

Understand how Java is designed to be platform-independent — the Write Once, Run Anywhere principle, and how the JDK, JRE, and JVM fit together.

Last reviewed: January 2025

·Java 8Java 11Java 17Java 21
✅
Quick Understanding: Java source code (.java) is compiled into bytecode (.class) by the Java Compiler. That bytecode runs on any machine that has a JVM installed. This is the Write Once, Run Anywhere promise — the JVM is the bridge between your code and the operating system.

🔍 What Is It?

Java Architecture describes the complete pipeline from writing code to executing it:

1. Source Code (.java)

Human-readable Java code you write in an IDE.

2. Java Compiler (javac)

Converts .java files into .class files containing platform-neutral bytecode.

3. Bytecode (.class)

Not machine code, not source code — an intermediate representation that any JVM understands.

4. JVM (Java Virtual Machine)

Interprets or JIT-compiles bytecode into native machine instructions at runtime.

5. JRE (Java Runtime Environment)

JVM + standard class libraries. Enough to run Java programs.

6. JDK (Java Development Kit)

JRE + compiler + debugger + tools. Needed to develop Java programs.

7. Class Loader

Loads .class files into memory when needed — not all at startup.

8. JIT Compiler (Just-In-Time)

HotSpot JVM identifies frequently executed code (hot paths) and compiles them to native machine code for speed.

🎯 Why Do We Need It?

Before Java, code written for Windows wouldn't run on Linux without recompilation or rewriting. Java solved this with the JVM abstraction layer:

  • →Platform independence — one JAR runs on Windows, Linux, macOS, embedded devices
  • →Security — bytecode verification before execution prevents malicious code
  • →Automatic memory management — Garbage Collector frees developers from manual malloc/free
  • →Ecosystem — JVM hosts Kotlin, Scala, Groovy — all compile to the same bytecode

In enterprise projects, this means you build one artifact (JAR/WAR) and deploy it to any server without recompilation.

🏗️ What Happens in Real Projects?

In a real enterprise project:

  • →Your CI/CD pipeline runs mvn package which invokes javac to produce a JAR
  • →That JAR is deployed to a Linux server (even if developers use macOS)
  • →The JVM on that server runs it without any code changes
  • →JVM flags like -Xmx4g -Xms2g control heap memory for the production server
  • →APM tools (Dynatrace, New Relic) attach as JVM agents to monitor performance
  • →GC logs are analyzed when production has memory issues

You'll tune JVM settings in Dockerfile or startup scripts:

java -Xmx4g -Xms2g -XX:+UseG1GC -jar myapp.jar

⚙️ How It Works

Compilation Phase:

  1. You run javac HelloWorld.java
  2. Compiler checks syntax, resolves types, generates HelloWorld.class
  3. .class file contains bytecode — a stack-based instruction set

Runtime Phase:

  1. You run java HelloWorld
  2. JVM's Class Loader loads HelloWorld.class + dependencies
  3. Bytecode Verifier checks the code is safe
  4. Interpreter begins executing bytecode
  5. JIT Compiler detects hot methods, compiles to native code
  6. Garbage Collector runs in background threads managing heap

Memory Areas:

  • →Heap — objects live here (GC manages this)
  • →Stack — method call frames, local variables (per thread)
  • →Metaspace — class metadata (replaced PermGen in Java 8)
  • →Code Cache — JIT-compiled native code

💻 Example

Java Architecture in Action — Tracing a simple program through the full Java pipeline.

java
// HelloWorld.java
public class HelloWorld {
    public static void main(String[] args) {
        String message = "Hello, Enterprise!";
        System.out.println(message);
    }
}

🤔 Common Confusions

❓ Is Java compiled or interpreted?

Both. Java source is compiled to bytecode (compiled step). The JVM then interprets bytecode OR JIT-compiles hot paths to native code (interpreted/compiled step). Modern JVMs are primarily JIT-compiled for performance.

❓ What is the difference between JDK, JRE, and JVM?

JVM runs bytecode. JRE = JVM + standard libraries (enough to run apps). JDK = JRE + compiler + tools (needed to develop). As a developer you install the JDK. Since Java 11, Oracle no longer ships a standalone JRE — you use the JDK everywhere.

❓ Does Java truly run identically on all platforms?

Mostly yes, but edge cases exist: file path separators (/ vs \), line endings, locale-sensitive operations, and native code via JNI are platform-specific. Pure Java code with no native dependencies is genuinely portable.

🚨 Common Production Issues

OutOfMemoryError: Java heap space — heap is too small for the workload. Fix: increase -Xmx or find memory leaks with heap dump analysis.

High CPU from GC — GC spending more time collecting than your app spends working. Fix: tune GC, reduce object allocation, switch to G1GC or ZGC.

Slow startup time — Class loading and JIT warmup takes time. Fix: use GraalVM Native Image for instant startup, or JVM class data sharing (-Xshare:on).

Metaspace OOM — Too many classes loaded (common with reflection-heavy frameworks). Fix: increase -XX:MaxMetaspaceSize or fix classloader leaks.

✅ Best Practices

Always set both -Xms and -Xmx to the same value in production to avoid heap resizing pauses.

Use G1GC (Java 9+) as default; switch to ZGC for latency-sensitive applications (Java 17+).

Enable GC logging in production — it is the first diagnostic tool for memory issues.

Use LTS releases (Java 8, 11, 17, 21) in production for long-term support.

Profile before optimizing — JVM JIT is excellent; most optimization is premature.

🏛️ Architect's Note

Senior Architect's Perspective

In microservices, JVM startup time matters. A traditional JVM app takes 5–30 seconds to start. For Lambda/serverless or rapid scaling, consider GraalVM Native Image (compiles to native binary, starts in milliseconds). For long-running services, standard JVM with JIT is faster at peak throughput than native image. Choose based on your scaling pattern.

💬 Frequently Asked Questions

Which Java version should I use in 2025?

Java 21 (LTS) for new projects. Java 17 (LTS) if your ecosystem has not caught up. Avoid Java 8 for new projects — it lacks records, sealed classes, text blocks, and modern APIs. Check your framework compatibility: Spring Boot 3.x requires Java 17+.

What is GraalVM and when should I use it?

GraalVM is an alternative JVM with a Native Image compiler that AOT-compiles Java to a native binary. Use it for serverless functions, CLIs, and microservices where fast startup and low memory are critical. Avoid it for applications that rely heavily on reflection, dynamic class loading, or JVM-specific profiling tools.

What is the difference between HotSpot JVM and OpenJ9?

HotSpot (Oracle/OpenJDK) is the standard JVM — best peak throughput. OpenJ9 (IBM/Eclipse) uses less memory at startup and is faster to start, at the cost of slightly lower peak throughput. For cloud deployments where memory cost matters, OpenJ9 is worth evaluating.

🎯 Key Takeaways

1Java compiles to bytecode, not native machine code — the JVM handles the platform translation
2JDK = development tools + JRE; JRE = JVM + standard libraries
3JIT compilation makes Java fast for long-running applications
4JVM memory: Heap (objects), Stack (frames), Metaspace (class metadata)
5Always tune -Xmx and enable GC logging in production
6Use Java 17 or 21 LTS for new projects

🎯 Practice this topic in interviews

↗ Where this topic fits

Sources

Sources / References

Use these Core Java references to verify the concept in official docs and continue into the most relevant SplashRide pages.

Related SplashRide pages