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.
TL;DR: JVM (Java Virtual Machine) là máy ảo đọc và chạy bytecode file .class — nó là động cơ thuần. JRE (Java Runtime Environment) = JVM cộng thư viện chuẩn Java, đủ để chạy một app đã build sẵn. JDK (Java Development Kit) = JRE cộng công cụ biên dịch như javac và jar, cần để viết và build code. Quan hệ là lồng nhau: JDK chứa JRE chứa JVM. Quy tắc chọn: developer luôn cài JDK; production server hoặc Docker image có thể dùng JRE để nhẹ hơn; máy chỉ chạy app desktop dùng JRE là đủ.
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 được và nâng cấp được xe.
Ánh xạ sang Java:
| Xe hơi | Java |
|---|---|
| Độ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 |
- 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).
Bài 01 đã giới thiệu bytecode cùng JVM qua analogy; ở đây ta phân biệt rõ JVM, JRE và JDK.
JVM làm ba việc chính:
- Load file
.classvào bộ nhớ - Verify bytecode (kiểm tra không có lệnh nguy hiểm)
- 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, streamsjava.net— HTTP, socket, URLjava.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:
| Tool | Lệnh | Dùng để |
|---|---|---|
| Compiler | javac | Compile .java sang .class |
| Launcher | java | Chạy app từ .class hoặc .jar |
| Archiver | jar | Đóng gói thành .jar file |
| Disassembler | javap | Xem bytecode của .class |
| Debugger | jdb | Debug chương trình đang chạy |
| Documentation | javadoc | Generate HTML docs từ Javadoc comments |
| Profiler | jconsole | Monitor JVM heap, threads, GC — VisualVM mạnh hơn nhưng là download riêng (tách khỏi JDK từ Java 9) |
| Key tool | keytool | Quả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 Java | JDK | Cầ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 app | JDK hoặc JRE | JDK để có thêm monitoring tools; JRE đủ nếu chỉ run |
| CI/CD pipeline build + test | JDK | Cần compile và chạy test |
Docker container chạy .jar | JRE hoặc custom runtime (jlink) | Tối ưu size, chỉ include module cần dùng |
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 — nhìn tổng quan
Hiểu sơ kiến trúc JVM giúp bạn đọc được stack trace và hình dung khi nào lỗi OutOfMemoryError xuất hiện. Đây chỉ là cái nhìn tổng quan ở mức nhập môn — chi tiết từng phần thuộc course nâng cao.
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)"]
stack["JVM Stacks<br/>(frames per thread)"]
end
gc["Garbage Collector"]
end
src --> cl --> bv --> ee
ee --> rda
gc -.-> heapMỗi component chính làm một việc:
- ClassLoader — đọc file
.classtừ disk, đưa vào bộ nhớ rồi khởi tạo (load, link, initialize) trước khi class được dùng. - Bytecode Verifier — kiểm tra bytecode hợp lệ và an toàn kiểu trước khi chạy; đây là lý do code Java không thể đọc vùng nhớ tùy ý như C.
- Execution Engine — chạy bytecode bằng Interpreter ở lần đầu (chạy ngay nhưng chậm), rồi JIT Compiler biên dịch những method nóng (gọi nhiều) thành native machine code để chạy nhanh hơn ở steady state.
- Vùng nhớ — Heap chứa mọi object (đầy thì gặp
OutOfMemoryError: Java heap space); JVM Stack chứa stack frame của mỗi lần gọi method, mỗi thread một stack (tràn thì gặpStackOverflowError, thường do đệ quy vô hạn). Garbage Collector tự động dọn object không còn tham chiếu — bạn không gọifree().
Chi tiết Garbage Collector (G1, ZGC, Shenandoah...) và đầy đủ Runtime Data Area (Metaspace, PC Register, Native Method Stack...) sẽ học ở course Java Internals (tier 3). Ở nhập môn, bạn chỉ cần nắm bức tranh tổng quan trên.
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:
| Distribution | Nhà phát triển | Chi phí | Đặc điểm |
|---|---|---|---|
| Oracle JDK | Oracle | Miễn phí dev/test; trả phí production (từ Java 17) | Official, commercial support |
| Eclipse Temurin | Adoptium (Eclipse Foundation) | Miễn phí | Phổ biến nhất, khuyến nghị cho hầu hết |
| Azul Zulu | Azul Systems | Miễn phí (community); trả phí (premium) | LTS support dài, nhiều platform |
| Amazon Corretto | Amazon | Miễn phí | Optimize cho AWS, dùng trong Amazon production |
| GraalVM | Oracle + community | Community miễn phí; Enterprise trả phí | Native image (compile Java thành binary), polyglot |
| Microsoft OpenJDK | Microsoft | Miễn phí | Optimize cho Azure, Windows |
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.
Việc cài JDK (qua SDKMAN/Homebrew, cấu hình JAVA_HOME) và bước verify bằng chương trình Hello World đầu tiên được hướng dẫn từng bước ở hai bài tiếp theo: Cài đặt môi trường và Hello World.
7. 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 java và echo $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.
8. 📚 Deep Dive Oracle
Spec chính thức:
- JVM Specification SE21 — full spec kiến trúc JVM: ClassLoader, bytecode, memory areas, execution engine
- JDK 21 Tool Docs — tài liệu tất cả command-line tools: javac, java, jar, javap, jdb, jlink...
- JDK 21 API Docs — Javadoc toàn bộ Java Class Library
- JEP 439 — Generational ZGC — ZGC trong Java 21 (finalized)
- JEP 444 — Virtual Threads — Project Loom, virtual threads finalized trong Java 21
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.
9. Liên hệ các bài khác
- Java là gì — bài này dựa trên khái niệm bytecode và JVM đã giới thiệu ở đó; đọc lại nếu bạn còn mơ hồ vì sao Java cần một "máy ảo" để chạy.
- Cài đặt môi trường — áp dụng ngay quyết định "chọn JDK nào": bài đó hướng dẫn cài JDK (Temurin) qua SDKMAN/Homebrew và cấu hình
JAVA_HOME. - Compile và Run — đi sâu vào hai công cụ
javacvàjavacủa JDK mà bài này mới chỉ giới thiệu tên: vòng đời từ.javasang.classrồi chạy trên JVM.
10. Tóm tắt
- JVM = bytecode execution engine. Chạy file
.class, gồm ClassLoader + Verifier + Execution Engine (Interpreter + JIT) + GC + vùng nhớ. - 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ó hai vùng nhớ chính cần nhớ ở nhập môn: Heap (chứa object) và JVM Stack (chứa frame mỗi method call).
- JIT Compiler tăng tốc bằng cách compile hot methods thành native code; GC tự động dọn object không còn reference.
- Nhiều JVM distribution: Temurin (phổ biến nhất), Corretto (AWS), Oracle JDK (trả phí production), GraalVM (native image).
11. Tự kiểm tra
Q1Tại sao JVM phải là implementation khác nhau trên mỗi OS, trong khi bytecode lại portable?▸
Q2ByteCode Verifier làm gì trước khi JVM chạy code? Điều này bảo vệ bạn khỏi gì?▸
.class hợp lệ trước khi thực thi: operand stack không underflow/overflow, type của tham số khớp với opcode, không truy cập ngoài mảng, không gọi private method của class khác, final class không bị subclass... Bảo vệ JVM khỏi crash do bytecode hỏng (bị sửa tay hoặc sinh sai), và chặn bytecode độc cố tình vi phạm type safety — điều tối quan trọng khi JVM chạy code đến từ nguồn không tin cậy (applet cũ, plugin, downloaded class).Q3JIT Compiler khác Interpreter ở điểm nào? Tại sao JVM không JIT compile tất cả mọi method?▸
Q4Đồng nghiệp chỉ cài JRE rồi gõ `javac App.java` để build, máy báo "command not found". Thiếu cái gì? Để vừa viết vừa chạy code thì nên cài JVM, JRE hay JDK?▸
javac (trình biên dịch) nên không build được, vì thế lệnh báo not found. Để vừa viết vừa chạy phải cài JDK: JDK bao trùm JRE và bổ sung công cụ phát triển (javac, jar, javap, jdb). JVM không phải thứ cài riêng lẻ — nó nằm bên trong cả JRE lẫn JDK. Quy tắc: viết code → JDK; chỉ deploy để chạy → JRE đủ.Q5Bạ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?▸
eclipse-temurin:21-jre cho production. JRE nhỏ hơn JDK đáng kể — với image eclipse-temurin, bản JRE thường nhẹ hơn bản JDK khoảng 130-180MB (không có javac, javap, jdb), giảm attack surface (compiler không có mặt trong prod = kẻ tấn công không dùng nó được), giảm pull/deploy time. Chỉ cần JDK khi app phải compile code runtime (JSP, Groovy script, dynamic class generation). Tối ưu thêm: eclipse-temurin:21-jre-alpine (~90MB) hoặc jlink custom runtime.Bài tiếp theo: Cài đặt môi trường và Hello World đầu tiên
Bài này có giúp bạn hiểu bản chất không?
Hỏi đáp về bài này
Chưa có câu hỏi
Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).
Đặt câu hỏi đầu tiên