1. 为什么需要自己编译JDK17?
在开始动手之前,我们先聊聊为什么要自己编译JDK。很多人可能会问:直接从官网下载编译好的二进制包不香吗?确实,对于大多数开发者来说,直接使用预编译的JDK是最方便的选择。但如果你遇到以下场景,自己编译JDK就变得很有必要了:
- 你需要为特定硬件平台(如ARM架构)定制JDK
- 你想修改或扩展JDK的某些功能(比如添加新的JVM参数)
- 你需要调试JDK内部的实现细节(比如研究HotSpot虚拟机的工作原理)
- 你想为JDK贡献代码(OpenJDK是开源的,欢迎社区贡献)
我最近就因为需要研究JVM的GC日志实现细节,不得不自己编译JDK。在这个过程中踩了不少坑,也积累了一些经验,下面就把完整的编译过程分享给大家。
2. 编译环境准备
2.1 硬件要求
编译JDK是个资源密集型任务,建议准备:
- 至少16GB内存(32GB更佳)
- 至少100GB可用磁盘空间(SSD最佳)
- 多核CPU(8核以上能显著缩短编译时间)
提示:如果机器配置不够,可以尝试减少并行编译线程数,但编译时间会大幅增加。
2.2 操作系统选择
官方支持的平台包括:
- Linux(推荐Ubuntu 20.04 LTS)
- macOS(10.13及以上)
- Windows(需要WSL2或Cygwin)
我个人推荐使用Linux系统,因为:
- 依赖管理更方便
- 编译环境更接近生产环境
- 问题排查资料更丰富
2.3 软件依赖安装
以Ubuntu 20.04为例,需要安装以下依赖:
sudo apt update sudo apt install -y git build-essential libx11-dev libxext-dev libxrender-dev \ libxtst-dev libxt-dev libcups2-dev libfontconfig1-dev libasound2-dev \ libfreetype6-dev autoconf zip unzip如果是其他系统,可以参考OpenJDK官方文档中的 构建要求 。
3. 获取JDK17源码
3.1 克隆OpenJDK仓库
JDK17的源码托管在GitHub上:
git clone https://github.com/openjdk/jdk17u.git cd jdk17u如果网络连接不稳定,可以考虑使用国内镜像:
git clone https://gitee.com/mirrors/openjdk-jdk17u.git3.2 选择正确的分支
JDK17有多个更新版本,建议选择最新的稳定分支:
git checkout jdk-17.0.6+10 # 以最新发布的更新版本为准可以通过git tag -l查看所有可用版本。
4. 配置编译环境
4.1 设置Bootstrap JDK
编译JDK17需要一个已有的JDK作为引导(Bootstrap JDK),要求版本为JDK16或JDK17:
sudo apt install openjdk-17-jdk export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64验证Bootstrap JDK:
$JAVA_HOME/bin/java -version应该输出类似以下内容:
openjdk version "17.0.6" 2023-01-17 OpenJDK Runtime Environment (build 17.0.6+10) OpenJDK 64-Bit Server VM (build 17.0.6+10, mixed mode)4.2 运行配置脚本
JDK使用Autoconf系统进行配置:
bash configure --enable-debug --with-jvm-variants=server常用参数说明:
--enable-debug:生成带调试信息的版本--with-jvm-variants=server:编译server版JVM(默认)--disable-warnings-as-errors:将警告视为非致命错误
如果配置成功,会输出类似以下信息:
Configuration summary: * Debug level: fastdebug * HS debug level: fastdebug * JVM variants: server * OpenJDK target: OS: linux, CPU architecture: x86, address length: 645. 开始编译
5.1 执行编译命令
使用make命令开始编译:
make images这个命令会编译出完整的JDK镜像,包括:
- 完整的JDK(在
build/linux-x86_64-server-fastdebug/images/jdk) - 精简的JRE(在
build/linux-x86_64-server-fastdebug/images/jre)
5.2 控制编译过程
- 查看编译进度:
make LOG=info images - 并行编译(加快速度):
make JOBS=4 images(根据CPU核心数调整) - 只编译HotSpot VM:
make hotspot - 只编译javac编译器:
make java.compiler
编译过程可能需要30分钟到数小时,取决于机器性能。
6. 验证编译结果
6.1 检查编译产物
编译完成后,可以验证生成的JDK:
./build/linux-x86_64-server-fastdebug/images/jdk/bin/java -version应该输出类似:
openjdk version "17-internal" 2021-09-14 OpenJDK Runtime Environment (fastdebug build 17-internal+0-adhoc.user.jdk17u) OpenJDK 64-Bit Server VM (fastdebug build 17-internal+0-adhoc.user.jdk17u, mixed mode)注意这里的版本号包含"internal"和"fastdebug",表示这是我们自己编译的调试版本。
6.2 运行测试用例
为了确保编译的JDK功能正常,可以运行一些基本测试:
make test-tier1这个命令会运行一组基本的JVM和核心库测试。
7. 常见问题与解决方案
7.1 编译失败:缺少依赖
错误示例:
checking for freetype... configure: error: Could not find freetype!解决方案:
sudo apt install libfreetype6-dev7.2 内存不足
错误示例:
g++: fatal error: Killed signal terminated program cc1plus解决方案:
- 增加swap空间
- 减少并行编译线程:
make JOBS=2 images
7.3 版本不匹配
错误示例:
error: The supplied boot JDK (version 16) is not a valid JDK 17 image.解决方案:确保使用JDK17作为Bootstrap JDK。
8. 高级技巧
8.1 增量编译
修改源码后,可以只重新编译变更部分:
make hotspot8.2 生成IDE项目文件
生成Eclipse项目文件:
make eclipse-project生成IntelliJ IDEA项目文件:
make ide-project8.3 调试JVM
编译debug版本后,可以使用gdb调试JVM:
gdb --args ./build/linux-x86_64-server-fastdebug/images/jdk/bin/java -version9. 实际应用场景
9.1 修改JVM参数
假设我们想添加一个自定义的JVM参数:
- 修改
src/hotspot/share/runtime/globals.hpp,添加:
experimental(intx, MyCustomParam, 100, \ "A custom parameter for testing") \- 重新编译HotSpot:
make hotspot- 使用新参数:
./build/linux-x86_64-server-fastdebug/images/jdk/bin/java -XX:+UnlockExperimentalVMOptions -XX:MyCustomParam=2009.2 添加新的JNI方法
如果想在JDK中添加新的native方法:
- 在Java类中声明native方法
- 生成头文件:
javac -h ... - 在对应native文件中实现方法
- 重新编译对应模块
10. 性能优化建议
10.1 使用ccache加速编译
安装ccache:
sudo apt install ccache配置环境变量:
export CC="ccache gcc" export CXX="ccache g++"10.2 选择性编译
如果只研究特定模块,可以只编译相关部分:
- 只编译核心库:
make java.base - 只编译NIO模块:
make java.nio
10.3 使用tmpfs
将编译目录挂载到内存文件系统:
sudo mount -t tmpfs -o size=20G tmpfs /path/to/build/dir这能显著提高编译速度,但需要足够的内存。
11. 后续学习建议
成功编译JDK只是开始,如果想深入理解JDK实现:
- 从java.base模块开始阅读源码
- 重点关注:
- HotSpot虚拟机实现
- 核心类库(如java.lang, java.util)
- JNI机制
- 使用调试器单步跟踪关键流程(如类加载、方法调用)
- 参与OpenJDK社区讨论和贡献
我自己在阅读JDK源码时,发现从JVM启动流程(main.c的JLI_Launch方法)开始跟踪是个不错的切入点。