Java — Từ Zero đến Senior/Nhập môn & Tư duy lập trình/JVM, JRE, JDK — ba khái niệm nền tảng
2/7
~16 phútNhập môn & Tư duy lập trình

JVM, JRE, JDK — ba khái niệm nền tảng

Phân biệt JVM, JRE, JDK một lần cho rõ: cái gì chạy code, cái gì đủ để deploy, cái gì cần để viết code. Hiểu kiến trúc bên trong JVM.

Khi cài Java, bạn sẽ gặp ngay ba chữ viết tắt: JVM, JRE, JDK. Tài liệu nào cũng nhắc, nhưng ít nơi giải thích rõ cái nào làm gì và khi nào dùng cái nào.

Bài này làm rõ ba khái niệm đó — từ analogy dễ nhớ đến kiến trúc bên trong để bạn không còn mù mờ khi đọc docs hay cấu hình server.

1. Analogy — Xe hơi, động cơ, và xưởng sửa xe

Hình dung chiếc xe hơi:

  • Động cơ — trái tim của xe. Không có động cơ thì xe chỉ là khung sắt. Động cơ biến xăng thành chuyển động.
  • Xe hơi hoàn chỉnh = động cơ + xăng + ghế + điều hoà + đèn + bánh... Bạn ngồi vào và lái được mà không cần hiểu bên trong động cơ hoạt động thế nào.
  • Xưởng sửa xe = xe hoàn chỉnh + bộ công cụ (cờ lê, máy chẩn đoán, phụ tùng thay thế...). Thợ máy sửa đượcnâng cấp được xe.

Ánh xạ sang Java:

Xe hơiJava
Động cơJVM — chạy bytecode
Xe hoàn chỉnh (lái được)JRE = JVM + thư viện chuẩn
Xưởng sửa xe (làm được xe mới)JDK = JRE + compiler + debugger + tools

💡 💡 Cách nhớ

  • JVM: động cơ — chạy bytecode, không có gì khác
  • JRE: xe lái được — JVM + thư viện Java chuẩn (java.util, java.io...) đủ để chạy app
  • JDK: xưởng sửa xe — JRE + javac (compiler) + javap (disassembler) + jdb (debugger) + nhiều tool khác, đủ để viết và build app

2. Định nghĩa — ba cái một lần

2.1 JVM — Java Virtual Machine

JVM là chương trình phần mềm đọc và thực thi bytecode (file .class). Nó là "máy ảo" vì nó mô phỏng một CPU ảo với tập lệnh riêng (bytecode instruction set).

JVM làm ba việc chính:

  1. Load file .class vào bộ nhớ
  2. Verify bytecode (kiểm tra không có lệnh nguy hiểm)
  3. Execute bytecode — interpret hoặc JIT-compile thành native machine code

JVM không phải một thứ duy nhất: mỗi OS (Windows, macOS, Linux) có implementation JVM khác nhau, viết bằng C++. Đây là lý do bytecode portable còn JVM thì không.

2.2 JRE — Java Runtime Environment

JRE = JVM + Java Class Library (thư viện chuẩn Java).

Thư viện chuẩn bao gồm hàng nghìn class bạn dùng hàng ngày:

  • java.lang — String, Integer, Math, System, Thread...
  • java.util — ArrayList, HashMap, Collections, Optional...
  • java.io / java.nio — đọc/ghi file, streams
  • java.net — HTTP, socket, URL
  • java.time — LocalDate, ZonedDateTime (từ Java 8)

Trước Java 9: JRE là download riêng biệt, nhẹ hơn JDK. Từ Java 9+: JRE không còn là bản phân phối riêng nữa — Oracle không release JRE standalone. Bạn dùng JDK hoặc tạo custom runtime bằng jlink.

2.3 JDK — Java Development Kit

JDK = JRE + development tools. Những tool quan trọng nhất:

ToolLệnhDùng để
CompilerjavacCompile .java sang .class
LauncherjavaChạy app từ .class hoặc .jar
ArchiverjarĐóng gói thành .jar file
DisassemblerjavapXem bytecode của .class
DebuggerjdbDebug chương trình đang chạy
DocumentationjavadocGenerate HTML docs từ Javadoc comments
Profilerjconsole, jvisualvmMonitor JVM heap, threads, GC
Key toolkeytoolQuản lý certificates, keystores

3. Quan hệ bao nhau

Ba thứ này không ngang hàng — chúng lồng nhau:

flowchart TD
  jdk["JDK<br/>(Java Development Kit)"]
  jre["JRE<br/>(Java Runtime Environment)"]
  jvm["JVM<br/>(Java Virtual Machine)"]
  tools["javac + jar + javap + jdb + javadoc + ..."]
  stdlib["Java Class Library<br/>(java.lang, java.util, java.io, java.net ...)"]
  engine["Bytecode Execution Engine<br/>(ClassLoader + Verifier + JIT + GC)"]

  jdk --> tools
  jdk --> jre
  jre --> stdlib
  jre --> jvm
  jvm --> engine

Nói cách khác: JDK ⊃ JRE ⊃ JVM.

4. Khi nào dùng gì?

Bạn làCần gìLý do
Developer viết code JavaJDKCần javac để compile, jdb để debug
End-user chạy app Java (desktop)JRE (hoặc JDK)Chỉ cần chạy, không cần compile
Production server chạy appJDK hoặc JREJDK để có thêm monitoring tools; JRE đủ nếu chỉ run
CI/CD pipeline build + testJDKCần compile và chạy test
Docker container chạy .jarJRE hoặc custom runtime (jlink)Tối ưu size, chỉ include module cần dùng

💡 💡 Quy tắc thực tế

Ngày nay, developer luôn cài JDK. Câu hỏi "JRE hay JDK" chủ yếu liên quan đến production server và Docker image size. Với Docker, nhiều team dùng jlink để tạo minimal JRE chỉ chứa modules ứng dụng cần — giảm image từ ~300MB xuống còn ~50-80MB.

5. Kiến trúc bên trong JVM

Hiểu kiến trúc JVM giúp bạn đọc được stack trace, hiểu OutOfMemoryError, và tuning GC về sau. Đây là cái nhìn tổng quan — mỗi component sẽ có bài riêng sâu hơn.

flowchart TD
  src["HelloWorld.class<br/>(bytecode input)"]

  subgraph jvm_box["JVM"]
    cl["ClassLoader<br/>Load + Link + Initialize"]
    bv["Bytecode Verifier<br/>Security check"]
    subgraph ee["Execution Engine"]
      interp["Interpreter<br/>(first run -- slow)"]
      jit["JIT Compiler<br/>(hot code -- native speed)"]
    end
    subgraph rda["Runtime Data Area"]
      heap["Heap<br/>(objects, arrays)"]
      stack["JVM Stacks<br/>(frames per thread)"]
      meta["Metaspace<br/>(class metadata)"]
      pc["PC Registers"]
    end
    gc["Garbage Collector<br/>(G1, ZGC, Shenandoah ...)"]
  end

  src --> cl --> bv --> ee
  ee --> rda
  gc -.-> heap

5.1 ClassLoader — tải và khởi tạo class

ClassLoader là component đầu tiên, làm 3 việc theo thứ tự:

  1. Loading — đọc file .class từ disk/network, tạo Class object trong memory
  2. Linking — verify bytecode, cấp phát bộ nhớ static, resolve symbolic references
  3. Initialization — chạy static initializer block, gán giá trị static field

Java có 3 ClassLoader mặc định theo cấp bậc:

  • Bootstrap ClassLoader — load java.lang, java.util... (built-in, viết bằng C++)
  • Platform ClassLoader (trước Java 9 là Extension CL) — load java.sql, java.xml...
  • App ClassLoader — load class của ứng dụng bạn viết

💡 💡 Cách nhớ

ClassLoader giống thủ thư: bạn cần quyển sách (class), thủ thư tra danh mục (tìm file .class), lấy sách về, kiểm tra còn nguyên vẹn không (verify), rồi đăng ký vào hệ thống (initialize).

5.2 Bytecode Verifier — bảo mật trước khi chạy

Trước khi execute, JVM chạy Bytecode Verifier để đảm bảo:

  • Bytecode không vi phạm quy tắc kiểu (type safety)
  • Không có stack overflow/underflow
  • Không truy cập vùng nhớ ngoài phạm vi cho phép
  • Không convert kiểu bất hợp pháp

Đây là lý do code Java không thể trực tiếp đọc vùng nhớ tùy ý như C — JVM bắt lỗi trước khi code chạy.

5.3 Execution Engine — interpret vs JIT

Execution Engine thực thi bytecode qua 2 con đường:

Interpreter (lần đầu):

  • Đọc và thực thi từng bytecode instruction
  • Không cần warm-up, chạy ngay
  • Chậm (mỗi instruction phải decode + execute)

JIT Compiler (sau khi "warm up"):

  • Phát hiện "hot methods" (gọi nhiều lần — ngưỡng mặc định ~10,000 lần)
  • Compile toàn bộ method thành native machine code
  • Cache native code → lần sau gọi thẳng machine code, không qua interpreter
  • Có thể nhanh bằng C++ ở steady state

JIT không compile tất cả — chỉ compile hot code. Những method gọi hiếm vẫn interpret để tránh lãng phí compile time.

5.4 Runtime Data Area — bộ nhớ JVM

VùngMô tảScope
HeapChứa tất cả objects và arraysChia sẻ toàn JVM
JVM StackStack frames cho method calls (local variables, operand stack, return address)Mỗi thread một stack
MetaspaceMetadata của class (tên field, tên method, bytecode...)Chia sẻ toàn JVM
PC RegisterProgram Counter — địa chỉ instruction đang thực thiMỗi thread một PC
Native Method StackStack cho native methods (JNI)Mỗi thread

Khi bạn thấy lỗi OutOfMemoryError: Java heap space — Heap đầy. StackOverflowError — JVM Stack đầy (thường do recursion vô hạn).

5.5 Garbage Collector — dọn rác tự động

GC tự động giải phóng objects không còn được tham chiếu. Bạn không gọi free() — JVM lo.

Java 21 có nhiều GC algorithm, mỗi cái có trade-off khác nhau:

GCĐặc điểmDùng khi
G1 GCDefault từ Java 9. Throughput + latency cân bằngHầu hết app
ZGCPause time < 1ms, scalable đến TB heapLatency-sensitive (trading, gaming)
ShenandoahConcurrent, pause ngắnApp cần low latency, Red Hat maintained
Serial GCSingle-threaded, overhead thấpEmbedded, container nhỏ
Parallel GCThroughput tối đa, pause dài hơnBatch processing

Chi tiết GC sẽ có ở module tuning. Bây giờ chỉ cần nhớ: GC tự động, không cần gọi tay.

6. Các JVM Distribution

"JVM" hay "JDK" không phải một sản phẩm duy nhất. Nhiều tổ chức build JDK từ cùng OpenJDK source, tạo ra JVM distributions khác nhau:

DistributionNhà phát triểnChi phíĐặc điểm
Oracle JDKOracleMiễn phí dev/test; trả phí production (từ Java 17)Official, commercial support
Eclipse TemurinAdoptium (Eclipse Foundation)Miễn phíPhổ biến nhất, khuyến nghị cho hầu hết
Azul ZuluAzul SystemsMiễn phí (community); trả phí (premium)LTS support dài, nhiều platform
Amazon CorrettoAmazonMiễn phíOptimize cho AWS, dùng trong Amazon production
GraalVMOracle + communityCommunity miễn phí; Enterprise trả phíNative image (compile Java thành binary), polyglot
Microsoft OpenJDKMicrosoftMiễn phíOptimize cho Azure, Windows

💡 💡 Chọn gì cho dự án mới?

Eclipse Temurin 21 LTS — miễn phí, phổ biến nhất, cộng đồng lớn, CI/CD integration tốt. Download tại adoptium.net. Nếu chạy trên AWS thì dùng Amazon Corretto không cần đổi gì — API tương đương Temurin.

Chi tiết về từng distribution, GraalVM native image, và jlink custom runtime sẽ có ở Module 13 — Môi trường và Tooling nâng cao.

7. Cài JDK — nhanh và đúng cách

7.1 Dùng SDKMAN (khuyến nghị — quản lý nhiều version)

# Cai SDKMAN
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"

# Cai Temurin 21
sdk install java 21.0.3-tem

# Kiem tra
java -version
# openjdk version "21.0.3" 2024-04-16
# OpenJDK Runtime Environment Temurin-21.0.3+9 (build 21.0.3+9)

7.2 Kiểm tra cài đặt

# Version Java
java -version

# Version compiler
javac -version

# Xem JAVA_HOME
java -XshowSettings:property -version 2>&1 | grep java.home

7.3 Hiểu JAVA_HOME

JAVA_HOME là biến môi trường trỏ tới thư mục cài JDK. Nhiều tool (Maven, Gradle, IDE) đọc JAVA_HOME để tìm JDK.

# macOS / Linux -- them vao ~/.zshrc hoac ~/.bashrc
export JAVA_HOME=$(/usr/libexec/java_home -v 21)  # macOS
export PATH=$JAVA_HOME/bin:$PATH

# Kiem tra
echo $JAVA_HOME
# /Users/you/.sdkman/candidates/java/21.0.3-tem

8. Verify — chạy Hello World để xác nhận JDK hoạt động

// HelloWorld.java
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, JVM!");
        System.out.println("Java version: " + System.getProperty("java.version"));
        System.out.println("JVM vendor:   " + System.getProperty("java.vm.vendor"));
        System.out.println("JVM name:     " + System.getProperty("java.vm.name"));
    }
}
# Compile
javac HelloWorld.java

# Chay
java HelloWorld

Output mẫu:

Hello, JVM!
Java version: 21.0.3
JVM vendor:   Eclipse Adoptium
JVM name:     OpenJDK 64-Bit Server VM

Nếu thấy output này — JDK đã hoạt động. Bài 3 sẽ đi vào cấu trúc chương trình Java đầu tiên.

9. Pitfall thực tế

Nhầm 1: Cài JRE standalone rồi không javac được. ✅ Cài JDK (bao gồm JRE + compiler). Từ Java 9+, JRE standalone không còn được release.

Nhầm 2: Máy có nhiều JDK, java -version ra version cũ. ✅ Kiểm tra which javaecho $JAVA_HOME. Dùng SDKMAN sdk use java 21.0.3-tem để switch.

Nhầm 3: Tưởng JVM là một — thực ra mỗi process Java chạy JVM instance riêng. ✅ Mở 3 tab terminal chạy 3 app Java → 3 JVM processes riêng biệt, heap riêng, GC riêng.

Nhầm 4: Dùng Oracle JDK cho production mà không có license. ✅ Dùng Eclipse Temurin hoặc Amazon Corretto — miễn phí hoàn toàn, API tương đương.

Nhầm 5: Trong Dockerfile dùng JDK full cho container chạy app — image nặng ~400MB. ✅ Dùng eclipse-temurin:21-jre-alpine (~90MB) hoặc jlink để tạo minimal runtime.

10. 📚 Deep Dive Oracle

ℹ️ 📚 Deep Dive Oracle (optional)

Spec chính thức:

Ghi chú đọc spec: JVM Spec Chapter 2 "The Structure of the Java Virtual Machine" mô tả chi tiết Runtime Data Areas (heap, stack, metaspace...). Chapter 5 "Loading, Linking, and Initializing" giải thích ClassLoader delegation model. Đây là nền tảng để hiểu ClassLoader issues và PermGen/Metaspace OOM errors.

11. Tóm tắt

  • JVM = bytecode execution engine. Chạy file .class, có ClassLoader + Verifier + JIT + GC + Runtime Data Areas.
  • JRE = JVM + Java Class Library. Đủ để chạy app Java.
  • JDK = JRE + development tools (javac, jar, jdb...). Cần để viết và build app.
  • JDK ⊃ JRE ⊃ JVM — developer luôn cài JDK.
  • JVM có nhiều vùng nhớ: Heap (objects), JVM Stack (method frames), Metaspace (class metadata).
  • JIT Compiler tăng tốc bằng cách compile hot methods thành native code.
  • GC tự động dọn objects không còn reference. Java 21 default là G1 GC.
  • Nhiều JVM distribution: Temurin (phổ biến nhất), Corretto (AWS), Oracle JDK (trả phí production), GraalVM (native image).

12. Tự kiểm tra

  1. Tại sao JVM phải là implementation khác nhau trên mỗi OS, trong khi bytecode lại portable?
  2. ByteCode Verifier làm gì trước khi JVM chạy code? Điều này bảo vệ bạn khỏi gì?
  3. JIT Compiler khác Interpreter ở điểm nào? Tại sao JVM không JIT compile tất cả mọi method?
  4. Khi nào một object trên Heap bị GC dọn? "Không còn reference" nghĩa là gì cụ thể?
  5. Bạn deploy app Java lên Docker. Nên dùng image base nào — eclipse-temurin:21-jdk hay eclipse-temurin:21-jre? Vì sao?

Bài tiếp theo: Cài đặt môi trường và Hello World đầu tiên