
1. 为什么需要自己编译JDK17在开始之前我们先聊聊为什么要自己编译JDK。虽然Oracle和各大厂商都提供了预编译好的JDK二进制包但自己动手编译有几个不可替代的优势深度定制你可以根据需求启用/禁用特定功能模块比如移除不需要的模块减小体积性能调优针对特定硬件架构进行优化编译比如针对ARM处理器优化学习原理这是理解JVM底层工作机制的最佳实践方式特殊需求比如需要修改HotSpot源码或添加调试信息我最近在为一个嵌入式项目定制轻量级Java运行时就不得不自己编译JDK。过程中积累了不少经验今天就来分享这个从源码到可执行JDK的完整过程。2. 环境准备与工具链配置2.1 硬件要求编译JDK17是个资源密集型任务建议准备CPU至少4核8线程以上更佳内存16GB起步32GB更稳妥磁盘SSD硬盘预留30GB空间实测数据在Ryzen 7 5800X8核16线程32GB内存的机器上完整编译耗时约35分钟。如果配置不足编译可能耗时数小时。2.2 操作系统选择官方支持以下平台Linux推荐Ubuntu 20.04 LTSmacOS 10.13Windows 10需WSL2我个人推荐使用Linux环境因为依赖管理更方便编译速度更快问题排查资料更丰富2.3 必要工具安装以Ubuntu为例执行以下命令安装基础工具链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关键工具说明build-essential包含gcc/g等编译工具autoconf配置脚本生成工具lib*dev各种图形/音频相关的开发库3. 获取JDK17源码3.1 源码仓库选择JDK源码主要有两个来源OpenJDK官方仓库推荐厂商定制版本如Adoptium我们使用OpenJDK官方源码git clone https://github.com/openjdk/jdk17u.git cd jdk17u小技巧如果网络不稳定可以使用国内镜像源git clone https://gitee.com/mirrors/jdk17u.git3.2 源码目录结构解析主要目录说明hotspot/JVM核心实现java.base/Java基础类库make/构建系统配置test/测试套件了解目录结构有助于后续的定制修改。4. 配置与编译过程4.1 引导JDK准备编译JDK需要一个已有的JDK作为引导这个引导JDK的版本必须比要编译的版本低1-2个版本。对于JDK17我们可以用JDK16或JDK15。下载并配置引导JDKwget https://download.java.net/java/GA/jdk16/7863447f0ab643c585b9bdebf67c69db/36/GPL/openjdk-16_linux-x64_bin.tar.gz tar -xzf openjdk-16_linux-x64_bin.tar.gz export PATH$PWD/jdk-16/bin:$PATH验证引导JDKjava -version # 应该显示JDK16的版本信息4.2 生成配置脚本运行自动配置bash configure --enable-debug --with-jvm-variantsserver \ --with-native-debug-symbolsinternal --with-target-bits64关键参数说明--enable-debug生成调试信息--with-jvm-variantsserver编译server版JVM--with-native-debug-symbolsinternal保留符号表--with-target-bits6464位架构4.3 开始编译执行完整构建make images这个命令会编译所有模块生成完整的JDK镜像打包成可分发格式编译过程会产生大量中间文件确保磁盘空间充足。如果遇到内存不足可以尝试make JOBS4 images限制并行编译任务数5. 验证与安装5.1 编译结果检查编译完成后生成的JDK位于cd build/linux-x86_64-server-release/images/jdk bin/java -version应该看到类似输出openjdk version 17-internal 2021-09-14 OpenJDK Runtime Environment (build 17-internal0-adhoc..jdk17u) OpenJDK 64-Bit Server VM (build 17-internal0-adhoc..jdk17u, mixed mode)5.2 安装到系统路径建议将编译好的JDK链接到标准位置sudo ln -s $PWD /usr/local/java/jdk17-custom然后更新环境变量添加到~/.bashrcexport JAVA_HOME/usr/local/java/jdk17-custom export PATH$JAVA_HOME/bin:$PATH6. 高级定制技巧6.1 模块化编译JDK17采用模块化设计可以只编译特定模块make jdk.jdi常用模块java.base基础模块jdk.compilerjavac编译器jdk.jlinkjlink工具6.2 调试符号处理如果需要调试HotSpot可以这样生成完整符号make images OBJCOPY: STRIP_POLICYno_strip这样生成的二进制会包含完整调试信息方便用gdb调试。6.3 交叉编译在x86上编译ARM版JDKbash configure --openjdk-targetaarch64-linux-gnu \ --with-toolchain-path/path/to/aarch64/toolchain需要提前准备好交叉编译工具链。7. 常见问题排查7.1 内存不足错误症状g: internal compiler error: Killed (program cc1plus)解决方案增加swap空间减少并行编译任务make JOBS27.2 依赖缺失错误症状configure: error: Could not find freetype!解决方案sudo apt install libfreetype6-dev7.3 版本冲突症状error: invalid suffix on literal这通常是gcc版本太旧导致需要升级到gcc-9sudo apt install gcc-9 g-9 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 908. 性能优化建议8.1 编译参数调优在configure时添加这些参数可以提升生成代码的性能--with-extra-cflags-O3 -marchnative \ --with-extra-cxxflags-O3 -marchnative8.2 链接时优化使用LTO优化--enable-link-time-optimization需要gcc 9支持可以提升5-10%性能。8.3 裁剪无用模块通过--with-jvm-features参数禁用不需要的功能--with-jvm-features-dtrace,-cds9. 实际应用案例9.1 嵌入式场景定制为树莓派定制最小化JDKbash configure --with-jvm-variantsminimal \ --disable-warnings-as-errors --with-jvm-features-dtrace,-cds \ --with-extra-cflags-Os -mcpucortex-a72 \ --openjdk-targetarmv7l-linux-gnueabihf9.2 添加调试信息开发JVM插件时的调试配置make CONFlinux-x86_64-server-fastdebug会生成带有调试符号的fastdebug版本。10. 后续维护建议10.1 增量编译修改源码后只需重新运行make images构建系统会自动检测变更部分。10.2 清理构建完全重新构建make clean make images10.3 版本管理建议将定制修改提交到独立分支git checkout -b my-custom-jdk git commit -am Add my custom patches这样下次可以从你的分支直接开始编译。