JDK 深度解析

在部署 Java 应用时,JDK 是最基础的依赖。但很多人对 JDK 的认知停留在"装了就能跑 Java"的层面,不清楚它的内部组成、JDK 与 JRE 的区别,以及运维场景下需要关注哪些点。本文系统梳理 JDK 的核心概念和实践要点。

目录

[一、JDK 是什么](#一、JDK 是什么)

二、核心组成

[2.1 编译器和运行时](#2.1 编译器和运行时)

[2.2 打包和文档工具](#2.2 打包和文档工具)

[2.3 调试和诊断工具](#2.3 调试和诊断工具)

[2.4 核心类库](#2.4 核心类库)

[三、JDK、JRE、JVM 的区别](#三、JDK、JRE、JVM 的区别)

四、运维实践要点

[4.1 版本选择](#4.1 版本选择)

[4.2 发行版选择](#4.2 发行版选择)

[4.3 安装与环境变量](#4.3 安装与环境变量)

[4.4 常用诊断命令](#4.4 常用诊断命令)

[4.5 JVM 基础参数](#4.5 JVM 基础参数)

五、总结


一、JDK 是什么

JDK(Java Development Kit)是 Java 开发工具包,包含了编译、运行、调试 Java 程序所需的全套工具和核心类库。简单来说,写 Java 和跑 Java 都依赖它。

JDK 不是一个单一的程序,而是一个工具集合。它的核心价值在于提供了从源码到运行的完整工具链,以及一套标准化的核心类库,使得 Java 程序可以"一次编写,到处运行"。

二、核心组成

2.1 编译器和运行时

|--------|-------------------------------------|
| 工具 | 作用 |
| javac | Java 编译器,将 .java 源码编译成 .class 字节码文件 |
| java | Java 启动器,启动 JVM 并加载运行字节码 |
| javap | 反编译工具,查看 .class 文件的字节码和结构 |

2.2 打包和文档工具

|---------|------------------------------------------|
| 工具 | 作用 |
| jar | 打包和解包 jar 文件,将多个 .class 和资源文件打包成一个可分发的单元 |
| javadoc | 根据源码中的注释生成 API 文档 |
| jlink | 模块化工具,创建自定义运行时镜像,减小部署体积 |
| jdeps | 依赖分析工具,分析类和模块的依赖关系 |

2.3 调试和诊断工具

这是运维人员最需要关注的部分,这些工具只有 JDK 才有,JRE 不包含:

|-----------|----------------------------------------|
| 工具 | 作用 |
| jdb | 命令行调试器 |
| jstack | 打印 Java 进程的线程栈,用于排查死锁、线程阻塞 |
| jmap | 导出堆转储文件,分析内存泄漏和对象分布 |
| jstat | 监控 JVM 统计信息,包括 GC、类加载、JIT 编译 |
| jcmd | 多功能诊断工具,JDK 8+ 推荐使用,可以替代 jstack、jmap 等 |
| jconsole | 图形化监控工具,查看内存、线程、GC 等实时信息 |
| jvisualvm | 更强大的图形化分析工具,支持性能分析和内存分析 |

2.4 核心类库

JDK 包含了 Java 标准库,从 Java 9 开始采用模块化设计(JPMS),核心类库被拆分为多个模块,其中最基础的是 java.base 模块,包含了 java.lang、java.util、java.io 等核心包。

三、JDK、JRE、JVM 的区别

这是 Java 领域最经典的概念区分,三者是包含关系:

JDK ⊃ JRE ⊃ JVM

开发工具 运行环境 虚拟机

(javac等) (类库) (执行字节码)

|--------|--------------------------|----------------------------------|--------------------|
| 名称 | 全称 | 能力 | 适用场景 |
| JVM | Java Virtual Machine | 只负责运行字节码,是一个抽象规范 | 内嵌在 JRE 中,不单独安装 |
| JRE | Java Runtime Environment | JVM + 核心类库,能运行 Java 程序 | 只运行应用、不需要开发和诊断的机器 |
| JDK | Java Development Kit | JRE + 开发工具 + 诊断工具,能开发和运行 Java 程序 | 开发机、构建机、需要排查问题的服务器 |

一个常见的误区是认为服务器上只需要 JRE。理论上没错,但实际运维中强烈建议安装 JDK,因为一旦应用出现性能问题或内存泄漏,没有 jstack、jmap 这些工具就无法排查。而且从 JDK 11 开始,Oracle 不再单独提供 JRE 下载,OpenJDK 的很多发行版也只提供 JDK,直接装 JDK 已经是标准做法。

四、运维实践要点

4.1 版本选择

Java 版本分为 LTS(长期支持)和非 LTS。生产环境必须使用 LTS 版本:

• Java 8:仍在大量老旧系统中使用

• Java 11:广泛使用的 LTS 版本

• Java 17:当前主流 LTS 版本

• Java 21:最新 LTS 版本,支持虚拟线程

非 LTS 版本(如 9、10、12、13、14、15、16、18、19、20)只提供 6 个月支持,不适合生产环境。

4.2 发行版选择

JDK 有多个发行版,功能基本一致,主要区别在于许可协议和支持周期:

|-----------------|----------------------------------|
| 发行版 | 说明 |
| Oracle JDK | Oracle 官方版本,商用需要付费 |
| OpenJDK | 开源参考实现,完全免费 |
| Eclipse Temurin | Eclipse 基金会维护的 OpenJDK 发行版,免费,推荐 |
| Amazon Corretto | AWS 维护的 OpenJDK 发行版,免费,长期支持 |
| Azul Zulu | Azul 系统维护的 OpenJDK 发行版 |

生产环境推荐使用 Eclipse Temurin 或 Amazon Corretto,免费且有长期安全更新。

4.3 安装与环境变量

安装 JDK 后需要配置 JAVA_HOME 和 PATH 环境变量:

复制代码
# 查看 Java 版本

java -version

javac -version

 

# 查找 Java 安装路径

which java

readlink -f $(which java)

 

# 配置环境变量(以 /usr/lib/jvm/java-17-openjdk 为例)

export JAVA_HOME=/usr/lib/jvm/java-17-openjdk

export PATH=$JAVA_HOME/bin:$PATH

在多版本环境中,可以使用 update-alternatives 管理默认 Java 版本,或者用 jenv、sdkman 等工具切换版本。

4.4 常用诊断命令

复制代码
# 查看 Java 进程

jps -l

 

# 查看线程栈(排查死锁、线程阻塞)

jstack <PID> > thread_dump.txt

 

# 导出堆转储(排查内存泄漏)

jmap -dump:format=b,file=heap.hprof <PID>

 

# 实时监控 GC

jstat -gcutil <PID> 1000

 

# 多功能诊断(推荐)

jcmd <PID> Thread.print

jcmd <PID> GC.heap_dump heap.hprof

jcmd <PID> VM.system_properties

4.5 JVM 基础参数

启动 Java 应用时,常见的 JVM 参数:

复制代码
# 堆内存设置

-Xms2g -Xmx2g          # 初始堆和最大堆,生产环境建议设为相同值避免动态调整

 

# GC 选择(Java 17 默认 G1,Java 21 默认 G1,可考虑 ZGC)

-XX:+UseG1GC

-XX:+UseZGC            # 低延迟 GC,适合大堆和响应时间敏感的场景

 

# GC 日志

-Xlog:gc*:file=gc.log:time,uptime,level,tags

 

# OOM 时自动导出堆转储

-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=/var/log/heapdump/

五、总结

JDK 是 Java 生态的基石,它不仅仅是"运行 Java 的东西",而是一套包含编译、运行、调试、诊断、打包的完整工具链。理解 JDK、JRE、JVM 的区别,选择合适的版本和发行版,掌握 jstack、jmap、jstat 等诊断工具,是运维 Java 应用的基本功。

在生产环境中,建议始终安装完整的 JDK 而非 JRE,选择 LTS 版本和免费的 OpenJDK 发行版,并配置好 OOM 堆转储和 GC 日志,以便在出现问题时能够快速定位根因。

相关推荐
邪修king17 分钟前
Re:Linux 系统编程篇 (十二):进程篇(一)基础与 fork 系统调用全解
linux·运维·服务器
SendTomo19 分钟前
send.wang:基于浏览器WebRTC实现无客户端文件互传
网络·python·网络协议·webrtc·p2p
牢姐与蒯21 分钟前
Linux进程(五).之环境变量
linux·运维·服务器·ubuntu
数智启示录27 分钟前
Doris精讲篇(六) 从第一批小文件到 -235:Doris 是怎样被正常写入拖死的
大数据·数据库·经验分享·面试·flink
智购科技自动售货机工厂30 分钟前
2026自动售货机异常重启根因分析:从日志挖掘到内存取证的技术实践~YH
开发语言·数据库·单片机·嵌入式硬件·人机交互
RisunJan32 分钟前
Android 面试知识点整理
android·面试·职场和发展
奈斯先生Vector36 分钟前
从“能调用”到“可运营”:AI Agent 进入多模型时代后的架构升级
java·javascript·数据库·人工智能·算法·架构·aigc
Escalating_xu37 分钟前
【C++类和对象(上)】从类的定义、封装与对象模型到内存对齐和 this 指针
开发语言·前端·c++
raindayinrain37 分钟前
深入理解Linux内核--系统调用,性能优化
linux·性能优化·系统调用·返回值·入参·内核态用户态地址访问