当前位置: 首页 > news >正文

【JVM原理详解】04-JDK与JRE与JVM关系辨析

JDK与JRE与JVM关系辨析

引言

“装JDK还是JRE?”“JDK和JVM到底什么关系?”“为什么JDK 9之后没有单独的JRE下载了?”——这些问题困扰着许多从入门到进阶的Java开发者。前三篇文章你已经了解了JVM如何执行字节码、发展出多样的实现,以及内部三大子系统的分工。本篇将从"工具链"和"部署环境"的视角,帮你彻底理清JDK、JRE、JVM三者的包含关系和职责分工,同时深入探讨JDK 9模块化带来的革命性变化,以及在实际工作中如何选择合适的JDK发行版。

JDK、JRE、JVM的包含关系

三者的关系可以用一句话概括:JDK包含JRE,JRE包含JVM。但这个表述过于简略,容易造成理解偏差。更精确的描述是:

┌─────────────────────────────────────────────────────────┐ │ JDK │ │ (Java Development Kit - Java开发工具包) │ │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ 开发工具 (Development Tools) │ │ │ │ javac, java, javap, javadoc, jar, │ │ │ │ jdb, jconsole, jshell (≥9), jlink (≥9) │ │ │ │ jstat, jmap, jstack, jcmd, jinfo │ │ │ └─────────────────────────────────────────────┘ │ │ │ │ │ ┌──────────────────────▼──────────────────────┐ │ │ │ JRE │ │ │ │ (Java Runtime Environment - 运行时环境) │ │ │ │ │ │ │ │ ┌──────────────────────────────────────┐ │ │ │ │ │ 运行时库 (Runtime Libraries) │ │ │ │ │ │ rt.jar / java.base 等模块 │ │ │ │ │ │ Java核心类库、资源文件 │ │ │ │ │ └──────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ ┌───────────────────▼─────────────────┐ │ │ │ │ │ JVM │ │ │ │ │ │ (Java Virtual Machine - 虚拟机) │ │ │ │ │ │ │ │ │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ │ │ 类加载器 │ 运行时数据区 │ │ │ │ │ │ │ │ │ 执行引擎 + GC │ │ │ │ │ │ │ └─────────────────────────────┘ │ │ │ │ │ └─────────────────────────────────────┘ │ │ │ │ │ │ │ │ ┌──────────────────────────────────────┐ │ │ │ │ │ 其他运行时组件 │ │ │ │ │ │ 平台库(如字体、音频) │ │ │ │ │ │ 部署技术(Java Web Start等,已弃用) │ │ │ │ │ └──────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ 辅助资源 (Auxiliary Resources) │ │ │ │ include/ (C头文件用于JNI) │ │ │ │ jmods/ (JDK模块文件, ≥9) │ │ │ │ legal/ (许可证文件) │ │ │ │ conf/ (JVM和JDK配置) │ │ │ └─────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘

JVM是最底层的基础。它只负责执行字节码——加载类、管理内存、执行指令、回收垃圾。JVM本身不包含Java标准类库。理论上你可以在一个只有JVM的裸机上执行字节码,但你会发现连System.out.println都无法使用,因为这个类存在于标准库中,而不是JVM中。

JRE在JVM的基础上增加了Java标准类库(如java.langjava.utiljava.io等)以及其他运行时需要的资源文件。JRE是"可以运行Java程序的最小环境"。它的定位是部署Java应用程序——用户只需要JRE就能运行你的jar包,无需安装JDK。

JDK在JRE的基础上进一步增加了开发工具。javac(编译器)、javap(反编译器)、javadoc(文档生成)、jconsole(监控工具)等都是JDK特有的,JRE中并不包含。JDK的定位是"开发Java程序所需的全套工具"。

JDK目录结构详解

以下是典型JDK安装目录的剖析(以JDK 17为例):

JDK_HOME/ ├── bin/ # 可执行文件,所有开发工具和运行时工具 │ ├── java* # JVM启动器 │ ├── javac* # Java编译器(JDK特有) │ ├── javap* # 字节码反编译器(JDK特有) │ ├── javadoc* # 文档生成器(JDK特有) │ ├── jar* # 打包工具 │ ├── jshell* # 交互式REPL(JDK 9+) │ ├── jlink* # 自定义运行时镜像(JDK 9+) │ ├── jpackage* # 平台安装包打包(JDK 14+) │ ├── jstat*/jmap*/jstack* # 诊断和监控工具 │ └── jdb* # 调试器 │ ├── conf/ # JDK配置(JDK 9+结构变更) │ ├── net.properties # 网络配置 │ └── security/ # 安全策略和证书 │ └── java.security │ ├── include/ # C/C++头文件,用于JNI开发 │ ├── jni.h │ ├── jvmti.h │ └── win32/jni_md.h # 平台相关的头文件 │ ├── jmods/ # JDK模块文件(JDK 9+新增) │ ├── java.base.jmod # 基础模块 │ ├── java.desktop.jmod # 桌面模块 │ ├── java.sql.jmod # SQL模块 │ └── ... │ ├── legal/ # 各模块的许可证信息(JDK 9+) │ ├── java.base/ │ ├── java.desktop/ │ └── ... │ └── lib/ # JDK内部使用的库 ├── src.zip # Java标准库源码(学习利器) ├── jrt-fs.jar # JRT文件系统提供者(JDK 9+) └── ...

值得注意的结构变化:

JDK 8及之前:JRE作为一个完全独立的子目录存在(jdk/jre/),内部包含自己的bin/lib/目录,其中lib/rt.jar包含了所有Java标准类库。如果你只安装了JRE而非JDK,你的安装目录就是JRE本身的目录结构。

JDK 9到JDK 10:JRE目录仍然存在于JDK中,但标准库已经从rt.jar迁移到了模块化格式(jmods/目录中的.jmod文件)。运行时JVM通过jrt://文件系统协议访问模块化类库。这种中间过渡状态存在的时间很短。

JDK 11及之后:JRE独立子目录正式消失。JDK目录本身就是运行时环境——运行Java程序所需的模块化类库通过jrt-fs.jar文件系统提供。如果需要部署时创建精简的JRE,使用jlink工具从JDK中生成一个自定义运行时镜像。这就是为什么Oracle官网从JDK 11起不再提供独立的JRE下载包。

rt.jar时代与Jigsaw模块化变革

rt.jar的辉煌与困境

在JDK 8及之前,Java标准类库被打包成一个巨大的rt.jar文件(Runtime JAR),大小约60MB,包含数万个类。这个文件是所有Java应用的基石——你在代码中使用的StringHashMapArrayList等都在这里。

rt.jar的问题是单体架构的顽疾

  • 任何Java应用都要加载整个rt.jar,即使你只是一个"Hello World"程序,所有类库的元数据都要被类加载器扫描一遍
  • 内部API的滥用泛滥sun.misc.Unsafesun.misc.BASE64Encoder等本应为内部使用的类,因为被放在具有包访问控制的公开位置,被无数第三方库直接调用,使得JDK升级变得异常困难
  • 部署体积庞大:要为嵌入式设备或Docker镜像打包JRE时,无法只选取需要的类库子集

Project Jigsaw与模块化系统

JDK 9引入的Java平台模块系统(JPMS,即Project Jigsaw)从根本上解决了上述问题。核心改变包括:

1. JDK自身被模块化rt.jar不再存在,取而代之的是约90个标准模块(Module)。例如:

java.base → java.lang, java.util, java.io 等核心类 java.sql → JDBC相关类 java.xml → XML处理类 java.desktop → AWT, Swing等GUI类 java.logging → 日志框架

java.base是唯一所有模块都隐式依赖的根模块。这种设计意味着一个不依赖GUI的应用在运行时完全不会加载java.desktop模块。

2. 强封装机制:模块通过module-info.java显式声明哪些包是公开API(exports),哪些包是内部实现。sun.misc.Unsafe等内部类默认不再对应用代码可见。这从编译器/运行时层面强制了API边界——不再只是文档上的"建议"。

3. 自定义运行时镜像jlink工具可以根据应用的模块依赖,生成一个只包含所需模块的精简运行时镜像:

# 为你的应用创建一个最小化的运行时jlink --module-path$JAVA_HOME/jmods\--add-modules java.base,java.sql\--outputmy-minimal-runtime\--strip-debug--compress=2

生成的精简运行时通常只有30-50MB,相比完整JRE的200MB+大幅减小。这在Docker镜像构建中尤为有价值——更小的镜像意味着更快的部署和更低的存储成本。

核心工具详解

java - JVM启动器

Java应用世界的"万能入口"。它的启动逻辑可以简化为:

  1. 加载JVM动态库(jvm.dll/libjvm.so
  2. 创建JVM实例并设置启动参数
  3. 通过类加载器找到主类(-jar指定jar包或直接指定类名)
  4. 调用主类的main(String[])方法

关键选项:

java-Xms512m-Xmx2g-XX:+UseG1GC-jarapp.jar# 设置堆大小和GCjava-cplib/*:myapp.jar com.example.Main# 手动指定classpathjava--add-opens java.base/java.lang=ALL-UNNAMED# JDK 9+: 开放封装-jarapp.jar

javac - Java编译器

.java源文件编译为.class字节码文件。关键选项:

javac-dout/ src/com/example/*.java# 指定输出目录javac--release8Main.java# 兼容JDK 8(同时控制source/target和API)javac-parametersMain.java# 保留方法参数名(JDK 8+)javac-g:noneMain.java# 不生成调试信息

javap - 字节码反编译器

学习JVM内部机制的利器。常用选项:

javap-cMain.class# 反编译方法字节码javap-verboseMain.class# 显示完整信息(常量池、属性等)javap-pMain.class# 包含私有成员javap-sysinfoMain.class# 显示类文件版本信息

jlink - 运行时镜像构建(JDK 9+)

jlink --module-path jmods\--add-modules java.base,java.logging\--outputmyjre

jpackage - 平台安装包生成(JDK 14+)

jpackage--inputtarget/--nameMyApp\--main-jar myapp.jar --main-class com.example.Main

实践:如何选择JDK发行版

市场上JDK发行版的选择令人眼花缭乱,以下是基于实际使用经验的建议框架:

选择决策树

是否必须Oracle商业支持且预算允许? ├── 是 → Oracle JDK (LTS版本,付费订阅获得补丁) └── 否 → 使用OpenJDK衍生发行版 ├── 通用场景 → Adoptium (Eclipse Temurin) │ 特点:Eclipse基金会背书,TCK合规,覆盖面最广 │ ├── 国内大规模部署 → 阿里Dragonwell │ 特点:JWarmup预热、多租户GC、阿里大规模验证 │ ├── 云原生微服务 → 考虑OpenJ9 + Adoptium │ 特点:启动快、内存低、共享类缓存 │ ├── 多语言/GraalVM → GraalVM Community / Oracle GraalVM │ 特点:Native Image + Truffle多语言支持 │ └── 嵌入式/IoT → Liberica JDK (BellSoft) 特点:ARM/MIPS等小众架构支持广

版本选择的核心决策

因素建议
稳定生产JDK 17 LTS 或 JDK 21 LTS
存量系统JDK 8(但需制定迁移计划)
前沿特性最新LTS版本
容器化部署JDK 17+(更好的容器感知)
Spring Boot 3JDK 17起(强依赖要求)

几个常见误区澄清

误区一:“Oracle JDK才是官方JDK”。实际上所有TCK合规的OpenJDK发行版在执行Java程序的功能上是等效的。Oracle JDK与其他发行版共享同一套OpenJDK源码,差异主要在于许可证、打包格式和支持服务。

误区二:“JDK 8最稳定,新版本有未知问题”。JDK 8发布至今超过10年,而JDK 17和21已经过了大规模生产验证。新版本在GC性能、容器感知、安全补丁方面有显著优势。固守JDK 8的唯一合理理由是应用依赖的框架/中间件不兼容更高版本,而这本身就是一个需要解决的工程债务。

误区三:“安装JDK就是安装了JVM”。严格来说是安装了包含JVM的完整开发环境。如果你在服务器上只部署应用,安装的是JRE或者通过jlink生成的精简运行时,而非完整的JDK。

实践要点

  1. 生产服务器不应安装完整JDK:安全意识上,生产服务器应遵循"最小权限"原则。JDK中包含jmapjstack等工具,在攻击者获得shell访问后可能被利用。理想的部署方案是通过jlink为应用定制精简运行时,既减小体积,又减少攻击面。

  2. Docker镜像中的JDK选择:推荐使用eclipse-temurin:17-jre(或对应的-jre-alpine)作为基础镜像。如果需要诊断工具,使用-jdk版本但在生产环境通过配置禁用远程调试和JMX。多阶段构建中可以仅在构建阶段使用JDK完整镜像,运行阶段切换为JRE精简镜像。

  3. 模块化迁移不是必须的:JDK 9的模块化系统对应用代码是可选的——你的应用即使没有module-info.java,仍然可以正常编译和运行。只有当你的库面向广泛的开发者公开分发时,模块化封装才具有较高的价值。对于内部应用,模块化迁移的投入产出比需要仔细评估。

  4. rt.jar消失的影响:如果你维护的代码中直接依赖了rt.jar的路径(如某些老旧的构建脚本或类加载器实现),在JDK 9+上需要适配。解决方案是使用-Xbootclasspath/a(不推荐,逐版本变化大)或直接使用标准API。

  5. javap是学习JVM的窗口:在技术成长过程中,javap -c -verbose是理解编译器行为、字节码指令、常量池结构的最有效工具。建议在遇到语法糖(如Lambda、字符串switch、try-with-resources)时,用javap查看编译器究竟生成了什么字节码,这比读100篇博客都管用。

小结

  • JDK ⊃ JRE ⊃ JVM 是三者包含关系的经典表述,JDK提供开发工具集,JRE提供运行时库,JVM是字节码执行的核心引擎
  • JDK 9的Jigsaw模块化系统的本质是将单体rt.jar拆分为可控的模块,带来了更强的封装和更精简的运行时
  • jlink工具允许创建只包含所需模块的自定义运行时,大幅减少部署体积,在容器化和微服务场景下价值突出
  • 选择JDK发行版时,优先考虑TCK合规的OpenJDK发行版(Adoptium是稳妥的首选),LTS版本是最务实的选择
  • JDK/JRE/JVM的关系辨析看似基础,其实构成了所有JVM知识的地基——理解"谁提供什么"是后续深入调优和排障的前提
http://www.jsqmd.com/news/1230880/

相关文章:

  • 加密货币钱包安全防护与2025年市场风险分析
  • 2026后端校招面试逻辑变革:从知识复述到能力涌现的实战指南
  • OpenCL、OpenGL与DirectX核心技术对比与应用指南
  • 主流深度学习框架性能对比与选型指南
  • Python+MySQL+Nginx技术栈实战指南
  • 不用Excel做报表之后:专业报表的标准正在被重新定义
  • VMP2 IAT修复技术:逆向分析与实战应用
  • 2026年寄大件快递省钱攻略:搬家家具物流全维度测评与比价指南 - 快递物流资讯
  • 英语绘本App哪家强?实测5款主流分级阅读工具,第3款让我意外
  • 2026年7月亲身到店探访东莞亨得利官方名表服务中心|官方地址及售后服务电话 - 亨得利官方博客
  • 2026年7月最新宝玑北京贵友大厦(通州店)维修保养服务电话 - 亨得利钟表维修中心
  • VBA OpenText方法Origin参数详解与跨平台文本处理
  • 领导力香港 EMBA 择校榜单|民企老板避坑必看,高性价比梯队实测
  • 鸿蒙 ArkTS 实战:Murder Mystery Party 从剧本推理聚会到兴趣社群工具完整解析
  • 强者制定规则,弱者认知退化:论“认知牢笼”的构建与社会危机的根源当规则的制定权与解释权被极少数人垄断,且规则的运行逻辑始终服务于该群体的利益时,这种“文明”的根基就是脆弱的,它必然会走向自我毁灭
  • Ubuntu下C++开发环境搭建与优化指南
  • AI领域岗位解析与转型指南:算法、工程与产品
  • LangGraph与LangChain:构建智能AI代理的双框架解析
  • Radial Pie Gauge图表:轻量级单指标可视化实现指南
  • vLLM 与 SGLang 推理框架性能横评:架构、吞吐与延迟的深度较量
  • 2026武汉婚姻家事律所选型指南:5家主流律所深度横评,按你的困境匹配最优解 - 商讯
  • 上海食品检测服务|本地企业GEO流量增长工具怎么选?高性价比工具推荐 - 子柔传媒
  • Windows C语言编程:Beep函数实现蜂鸣声与音频反馈
  • Claude Code智能编程助手:架构解析与实战应用指南
  • 模板驱动的文档自动化:从排版苦力到配置式内容生产
  • PCIe与存算一体技术融合的硬件加速革命
  • FastAPI+React TS构建高效AI Agent系统实战
  • 2026亚洲EMBA含金量测评|民企老板择校榜单,避坑必看
  • 2026 年 7 月佛山手工床垫工厂推荐|必然花开 MUSTBLOOM,高端天然手工床垫源头直选 - siouxx
  • 当ChatSQL遇上Oracle RAC:AI生成语句在RAC环境中的3种隐式锁冲突场景及秒级诊断模板