返回知识工坊

Learning Path

JVM 虚拟机:JDK、JRE 与 JVM 核心关系与运行机制记忆卡

通过剖析 JDK、JRE 和 JVM 的包含关系、Java 跨平台实现机制、`javac` 前端编译流程以及 `JRE` 核心类库加载原理,帮助读者快速构建 Java 运行时的底层认知模型。

入门4 张卡15 分钟发布于 2026年7月1日

路径目标

JVM 虚拟机:JDK、JRE 与 JVM 核心关系与运行机制记忆卡

本组记忆卡针对初学者极易混淆的 JDK、JRE、JVM 三者关系进行深度拆解,从职责边界、跨平台实现、编译器分工到核心类加载机制,提供可复述、可自测、可拓展的知识训练路径。

4 张知识卡4 个诊断问题4 个边界答案4 个记忆锚点4 个衍生拓展
01
外部资料

阐明 `JDK`、`JRE`、`JVM` 三者包含关系与职责

JDK(Java Development Kit)是 Java 开发工具包,包含编译器和调试工具;JRE(Java Runtime Environment)是运行环境,包含核心类库和 JVMJVM(Java Virtual Machine)是虚拟机,负责将字节码翻译成机器码。三者构成包含关系:JDK > JRE > JVM。开发者安装 JDK,而仅需运行程序的服务器安装 JRE 即可。

诊断题

既然 JDK 已经包含了 JRE,为什么在现代 Java 开发中,部署生产环境时往往只单独安装 JRE 或者更精简的运行时镜像,而不是直接部署完整的 JDK

答案骨架

我能理清三者的层级

  1. JVM 是核心抽象计算机,负责执行 .class 字节码,是实现跨平台的基础
  2. JRE 包含 JVM 和运行所需的基础类库(如 java.lang 等)
  3. JDK 是面向开发者的,在 JRE 基础上增加了 javacjavadoc 等开发工具
  4. 适用边界上,开发机必装 JDK,仅需运行的环境装 JRE 即可,以减少体积和安全风险。

边界追问

如果我们在服务器上只部署了 JRE,突然需要在线上动态编译一段 .java 代码,这能成功吗?为什么?

边界答案

无法成功。JRE 仅提供运行时环境,不包含 javac 等编译工具。若需动态编译 .java 文件,必须引入包含编译器的 JDK,或使用第三方的动态编译库。

记忆锚点

JDK 造车带工具,JRE 开车上马路,JVM 引擎跑字节码。

衍生拓展

  • 探索 Java 9 引入的模块化系统对 JRE 结构的改变。
  • 了解 jlink 工具如何生成自定义的轻量级 JRE 镜像。
  • 比较不同厂商(Oracle, OpenJDK)的 JDK 授权差异。

落地场景

假设我们要运行一个 Java 程序。开发时使用 JDK 中的 javacMain.java 编译为字节码:javac javac Main.java 。随后在测试环境中,只需 JRE 即可执行该程序,因为 JRE 中的 JVM 能够解释或即时编译这些 .class 文件:java java Main 。

打开资料
02
外部资料

说清 `JVM` 跨平台机制为什么依赖于底层操作系统

JVM 并不是一种跨平台的物理机器,而是运行在不同操作系统上的进程。它通过屏蔽底层操作系统的差异,提供统一的字节码执行环境。Java 程序编译后生成与平台无关的字节码(.class 文件),然后由针对特定平台(如 Windows、Linux)编写的 JVM 实现来执行。这解决了 C/C++ 等语言需为不同平台重新编译的问题。

诊断题

既然 Java 宣称'一次编写,到处运行',那么同一份 .class 字节码在 Windows 和 Linux 上运行时,JVM 在底层执行机制上是否有差异?

答案骨架

我能解释跨平台的底层原理

  1. 跨平台的关键在于中间层字节码(.class
  2. 编译器 javac 只生成与平台无关的字节码
  3. 字节码不能直接被硬件执行,必须由特定平台的 JVM 翻译
  4. 各操作系统的 JVM 实现不同,它们会将字节码转换为当前系统的机器指令,JVM 本身是不跨平台的。

边界追问

如果在代码中直接调用了 Windows 特有的系统库(如通过 JNI 调用 .dll 文件),编译出的 .class 在 Linux 上还能'到处运行'吗?

边界答案

不能。跨平台的边界在于不能使用特定操作系统的本地 API 或依赖。一旦通过 JNI 调用了平台特有的本地库(如 .dll),到了缺乏该库的 Linux 环境下就会抛出 UnsatisfiedLinkError

记忆锚点

代码不挑机器,是因为 JVM 挑机器;字节码通用,JVM 专用。

衍生拓展

  • 深入了解 JNI(Java Native Interface)的工作原理。
  • 研究字节码指令集规范是如何设计的。
  • 对比 GraalVM 是如何实现跨语言运行的。

落地场景

针对同样的文件操作代码,编译后在 Windows 上运行时,JVM 实现会调用 Windows API;在 Linux 上运行时,JVM 实现会调用 POSIX API。代码层只需写:java System.out.println("Hello OS"); ,底层由不同的 JVM 翻译。

打开资料
03
外部资料

解释 `javac` 编译器在前端编译中的核心职责

javacJDK 提供的前端编译器,它负责将开发者编写的 .java 源文件编译成 JVM 能识别的字节码 .class 文件。这个过程包括词法分析、语法分析、语义分析以及生成字节码。javac 不涉及具体的机器码优化,它把性能优化交给了 JVM 的后端编译器(如 JIT 编译器)。这保证了前端编译的跨平台统一性。

诊断题

在 Java 程序执行中,javac 编译与 JVM 内部的 JIT 编译(即时编译)有什么区别?它们分别在什么阶段发挥作用?

答案骨架

我能明确编译过程的两个阶段

  1. javac 属于前端编译,在开发阶段将 .java 编译为 .class
  2. JVM 的 JIT 编译器属于后端编译,在运行时将热点字节码编译为机器码
  3. 前端编译保证跨平台,只做基础检查
  4. 后端编译针对当前硬件架构做深度的机器码级性能优化,提升执行效率。

边界追问

如果一个方法只被调用了一次,JVM 会花费大量资源用 JIT 编译器把它编译成高度优化的本地机器码吗?

边界答案

不会。JIT 编译(如 HotSpot 的 C1/C2 编译器)有热点探测机制。只有被频繁执行达到特定阈值的方法或循环才会触发编译,否则仅通过解释器逐行执行,以节省编译开销。

记忆锚点

javac 管翻译(变字节码),JIT 管提速(变机器码)。

衍生拓展

  • 学习 HotSpot 虚拟机的分层编译机制。
  • 了解 AOT(Ahead-Of-Time)编译在现代 Java 中的应用。
  • 探究 javac 插件如何实现编译期代码生成。

落地场景

当我们执行 javac App.java 时,javac 检查类型与语法,并生成包含字节码的 App.class。当运行 java App 时,JVM 解释执行,发现 main 方法被高频调用后触发 JIT 编译优化:shell javac App.java java App 。

打开资料
04
外部资料

阐明 `JRE` 内核心类库(如 `java.lang`)的加载时机

JRE 提供了 Java 程序运行的基础环境,其核心是 JVM 和一系列内置的标准类库(如 rt.jar,或在 Java 9 之后变为 java.base 模块)。当 JVM 启动时,引导类加载器会优先加载这些最核心的类。这些类库提供诸如 StringThreadSystem 等基础功能的实现,保证了程序能正常调用基本 API。

诊断题

JVM 启动并准备执行我们的业务代码前,java.lang.String 等核心类是如何被找到并加载进内存的?普通开发者能否替换这些核心类?

答案骨架

我能说明核心类库的加载原理

  1. JRE 中包含支持运行的标准类库
  2. 启动时,JVM 依靠底层 Bootstrap ClassLoader 寻找核心类
  3. java.lang 等基础类最先被加载,以支撑系统运行
  4. 为了安全,开发者不能随意覆盖 java.* 包中的核心类,会触发安全异常。

边界追问

如果我们在项目中自己创建一个 java.lang.String 类,并尝试在程序中实例化,JVM 会使用我们的实现还是原生的实现?

边界答案

使用原生实现。JVM 的类加载机制采用双亲委派模型,加载请求会先委派给 Bootstrap ClassLoader。由于原生 java.lang.String 已在核心类库中存在,自定义的同名类将无法被加载,以此保障平台安全。

记忆锚点

JRE 是仓库,Bootstrap 管钥匙,核心类先入库。

衍生拓展

  • 深入研究双亲委派模型的作用与打破方式。
  • 探讨 Java 9 模块化系统对核心类加载路径的改变。
  • 了解自定义类加载器的应用场景。

落地场景

JVM 启动时,会自动加载 JRE 中的核心类库。例如我们在代码中直接使用 String,它其实是由底层类加载器从 java.base 模块中加载的:java String greeting = "Hello JRE"; System.out.println(greeting); 。

打开资料
JVM 虚拟机:JDK、JRE 与 JVM 核心关系与运行机制记忆卡 | 博击长空