自己编译JDK17实战:configure、make与HotSpot调试全解析

发布时间:2026/10/19 11:12:07
自己编译JDK17实战:configure、make与HotSpot调试全解析 先给一个直白的结论自己编译一个JDK17真的不难但整个过程可以分成“环境准备、configure、make、验证”四步每一步都有很多“看起来不关键、踩下去就翻车”的细节。我见过很多同事第一次尝试时卡在configure阶段反复装库还有人编译到一半内存不够只能重来所以这篇我尽量把那些容易忽略的坑提前说清楚。如果你只是日常写业务代码其实没必要自己编译JDK下载官方二进制包就已经够了。但如果你遇到下面这些情况目标平台没有现成的JDK包、需要往JVM里打内部补丁、想通过调试器看HotSpot源码逻辑、或者就是想把版本号改成自己公司的标识那就绕不开编译这条路。JDK17作为长期支持版本源码结构和构建系统已经相当成熟是很适合拿来实验的对象。这篇就是按“从零到一”的顺序手把手把流程走一遍最后再给你一份常见问题速查表。1. 准备工作先想清楚要什么再动手1.1 什么情况下才值得自己编译JDK自己编译JDK不是炫技而是被问题逼出来的选择。最常见的三种场景你可以对号入座。第一种是目标平台没有官方二进制包。很多自研芯片或者精简版操作系统官方只发布x86_64和aarch64的安装包你手里的平台没有现成产物这时候源码编译几乎是唯一路径。第二种是调试和学习HotSpot。看源码是一回事但真的想在类加载、JIT编译、GC回收的C源码里打断点就必须有一个带调试信息的自编译JDK。第三种是定制内部版本。比如公司内部有一个安全补丁或者你想默认开启某些JVM参数直接改源码重新构建比写一堆启动脚本要干净得多。反过来说如果只是从JDK17升级到某个小版本或者想换一个发行版直接下载安装包就好没必要自己编。自己编译的JDK在性能上不一定比官方构建好工程优化和平台验证也可能不足这一点心里要有数。1.2 Release、FastDebug、SlowDebug先选对调试级别JDK构建的调试级别直接影响后续开发效率建议动手前就想清楚。级别适合场景特点release日常使用、性能测试默认级别性能好无额外调试信息产物体积最小fastdebug大多数源码调试场景带断言、大量日志输出编译快运行速度比release慢但可接受slowdebug深入JVM底层调试调试信息最完整编译产物很大运行明显更慢如果你是第一次尝试我建议先用release把整个流程跑通确认环境没问题。之后想研究JVM再切到fastdebug。fastdebug的java -version输出会带fastdebug字样用起来比较直观也很方便确认当前到底用的哪个版本。1.3 一次构建到底需要多少“家底”编译JDK对硬件有一定要求但不需要夸张的服务器。磁盘方面源码包解压后大约3到4GB构建中间产物和最终JDK镜像加起来还要再占4到5GB。我习惯一次预留15GB空间避免中途不够用。内存方面8GB是一个勉强能跑的门槛16GB会比较舒服。并行编译时HotSpot的C编译会同时吃很多内存如果内存太小编到一半会收到“virtual memory exhausted”之类的错误。CPU核心数直接决定了等待时间。同一份JDK17源码4核机器可能要一个半小时以上8核大概40到60分钟16核机器20分钟左右就能出成品。当然这是release级别的参考值fastdebug会更快一点slowdebug则更慢。操作系统方面Linux是最顺的路线macOS装了Xcode命令行工具也能编Windows原生编译的依赖项非常繁琐强烈建议在Windows上先装一个Linux环境再动手。2. 环境准备过好依赖关configure才不会烦你2.1 编译器、make、autoconf一个都不能少JDK17的HotSpot代码要求支持C14的编译器GCC和Clang都可以。在Debian系发行版上我一般先装这一批基础工具sudo apt-get install build-essential autoconf make zip unzipbuild-essential里面带了gcc、g和基础库autoconf是configure阶段必需的zip和unzip是打包jmods时用到的。如果你用的是其他发行版按照对应的包管理器装同名的包即可。除了编译器还要留意几个运行库的头文件。JDK默认构建包含了完整的类库AWT和Swing图形部分依赖freetype、fontconfig、cups以及X11相关开发包。很多服务器是最小化安装做Java后端时不需要这些东西但编译JDK时会集体跳出来报错。我的经验是与其一个个排查不如直接把常见的依赖都装上节省来回折腾的时间。2.2 Boot JDK先有鸡还是先有蛋JDK的编译有一个“引导”机制你不可能用空气构建出一个编译器必须先有一个已经能运行的JDK来编译新JDK的Java部分代码。这个用来起手的JDK就叫Boot JDK。JDK17构建时官方要求Boot JDK的版本为JDK16。版本太老或者太新都可能被configure拒绝我建议直接下载一个官方发布的JDK16安装包解压到一个固定目录比如/opt/jdk-16后面配置时用--with-boot-jdk参数指定。有一种常见误解是我机器上正好装了JDK17能不能拿它当Boot JDK编另一个JDK17理论上可以但版本策略并不放心最好按官方要求的版本走省得configure阶段因为版本不符报出莫名其妙的问题。2.3 configure前的环境自检开始configure之前我习惯先跑一遍环境检查确认工具链正常。直接在终端执行bash --version gcc --version make --version autoconf --version java -version df -h . free -h这些命令分别确认shell、编译器、构建工具、autoconf、Boot JDK和磁盘内存状态。尤其是df -h .很多人漏看最后磁盘满了才后悔。你不需要装到“最新版”只要在configure脚本支持的大版本范围内就够用。老版本GCC如果编译失败可以先考虑升级而不是马上怀疑代码有问题。3. 拉取源码与配置构建configure不是玄学3.1 获取JDK17源码我推荐拉jdk17u分支JDK的源码获取方式很灵活可以下载官方源码包也可以直接从源码仓库拉取。日常学习我更喜欢拉Git仓库因为后面想自己打补丁时Git分支管理比直接改压缩包里的文件舒服得多。拉取时建议选jdk17u分支这个分支是JDK17的更新版本持续集成后续的修复和安全性改进比初始GA代码更稳。命令大概长这样git clone --depth 1 --branch jdk17u https://github.com/openjdk/jdk17u.git--depth 1表示浅克隆只拉最新代码速度很快。如果你是想要完整的历史记录就不要加这个参数。克隆完成后源码目录下会看到src、make、configure脚本等这些都很好辨认。3.2 configure究竟在干什么JDK的构建沿用了开源社区常见的“configure make”体系。简单说configure负责把你的环境“摸一遍底”然后生成对应的构建配置和Makefile。它不是随便跑跑而是会检测操作系统、CPU架构、C编译器版本、Boot JDK位置、各类依赖库是否存在最后把所有结论写进构建配置。configure阶段最实用的文件是config.log。如果配置失败不要凭感觉瞎猜直接打开config.log看最后几十行绝大多数原因都被清清楚楚写在里面。3.3 常用configure参数照着抄就行JDK的configure参数很多但日常构建用到的就那么几个。我整理了一份常用清单参数作用使用建议--with-boot-jdk指定Boot JDK路径必须避免configure自动找错版本--with-jvm-variants选择JVM变体默认server即可无需改动--with-debug-level设置调试级别release、fastdebug、slowdebug三选一--enable-debug等于开启fastdebug想调试时使用相当于简写--with-native-debug-symbols保留本地调试符号设internal方便后续用gdb--disable-warnings-as-errors把警告不作为错误编译器较新或较老时建议加上--with-version-string自定义JDK版本号想定制版本时使用一个比较稳妥的release构建配置可以这样写cd jdk17u bash configure \ --with-boot-jdk/opt/jdk-16 \ --with-jvm-variantsserver \ --with-debug-levelrelease \ --disable-warnings-as-errors \ --with-native-debug-symbolsinternalconfigure成功之后终端会输出一份配置摘要里面会明确告诉你构建目录在哪一般是build/linux-x86_64-server-release这样的格式。如果这里报错优先翻config.log然后把缺的依赖装好再重新运行。3.4 从release切换到fastdebug想切到fastdebug调试版本不需要重新拉源码只需要重新configure一次bash configure \ --with-boot-jdk/opt/jdk-16 \ --with-jvm-variantsserver \ --with-debug-levelfastdebug \ --disable-warnings-as-errors重新configure之后构建目录会变成build/linux-x86_64-server-fastdebug。这里是很多人容易踩坑的地方改完调试级别后如果发现产物没变化先检查是不是跑错了构建目录。JDK的构建系统会给不同配置单独建目录不会覆盖之前的release产物。4. 正式编译从make到第一杯新鲜JDK4.1 挑对make目标JDK的make目标有好几个最常用的是images。make images会生成一个完整的JDK镜像包含bin、conf、lib、jmods等常规目录结构这个镜像可以直接当JAVA_HOME使用。如果你只想跑点基础测试可以用make加其他目标但作为入门认准images就够了。清理构建产物时用make clean它会按当前配置清理对应构建目录比手动删目录安全。4.2 并行编译参数与日志留存并行编译能大幅缩短时间但也要看内存。我常用的命令是make JOBS8 images 21 | tee build.logJOBS8表示用8个并行任务。核数多但内存小的机器不建议盲开高JOBSHotSpot编译时会同时起多个编译器进程内存峰值会迅速上涨。如果内存只有8GBJOBS4会比较稳16GB内存可以尝试JOBS8甚至更高。tee build.log会把完整日志同时输出到屏幕和文件。编译一旦出错直接去build.log的末尾找线索比在终端里往上翻页高效得多。这个习惯我从第一次编译开始就保持后面几乎每次都靠它定位问题。4.3 漫长的等待里发生了什么执行make之后你会看到大量编译输出。这里简单解释一下整个过程大致分为几个阶段用Boot JDK编译JDK自身Java类库代码编译HotSpot虚拟机的C源码生成jmods模块文件组装最终的jdk目录结构其中HotSpot的编译是最耗时的。--with-native-debug-symbolsinternal会保留调试符号产物会变大但后续调试时很有价值。如果中途因为某个错误中断不用太担心修复后重新执行同一条make命令构建系统会做增量编译只重编受影响的部分。只有改了configure参数或者源码结构发生大变化时才需要考虑make clean后从头来。4.4 编译产物在哪里编译完成后最终产物就在configure提示的构建目录下。以上面命令为例路径大概是build/linux-x86_64-server-release/jdk这个jdk目录就是一套完整的JDK。里面的bin/java就是可执行文件lib/server/libjvm.so就是HotSpot核心动态库。把它拷贝到别的同平台机器上只要目录结构完整就能直接当JDK用。5. 验证产物与进阶玩法5.1 基础验证java -version和javac拿到一套新鲜JDK先做最基本的冒烟验证。用完整路径执行版本命令build/linux-x86_64-server-release/jdk/bin/java -version正常会看到类似这样的输出openjdk version 17.0.x ...接着可以试一下编译器写一个最简单的Java文件跑一遍build/linux-x86_64-server-release/jdk/bin/javac Hello.java build/linux-x86_64-server-release/jdk/bin/java Hello能编译能运行说明Java部分的模块基本没有大问题。如果你用了--with-version-string这里的版本号会显示成你自定义的内容方便确认当前二进制就是自己编的那个。5.2 让真实应用跑在自己编译的JDK上基础验证只是开胃菜。我更建议把一套实际的Java应用跑上来比如一个包含数据库连接、并发任务、文件读写的内部测试服务。运行时可以这样指定JDKexport JAVA_HOME/path/to/build/linux-x86_64-server-release/jdk export PATH$JAVA_HOME/bin:$PATH java -jar myapp.jar启动日志里可以看到模块加载顺序、GC策略等。重点观察两点应用能否正常启动以及持续跑一段时间后有没有异常崩溃。自编译JDK最大的风险不在“能不能编出来”而在“运行时会不会因为某些平台差异或源码配置问题出现诡异行为”所以真实应用的压测是必须的一步。5.3 用一个可调试的JDK看JVM源码当你把--with-debug-levelfastdebug的产物编译出来后java -version会明确显示fastdebug后缀。fastdebug版本带着大量断言和调试输出运行速度比release慢但用来学习JVM内部机制是极好的。如果你真的想跟踪HotSpot某个C函数slowdebug加上--with-native-debug-symbolsinternal是更完整的选择可以用调试器在类加载、GC日志、JIT编译路径上打断点。改完源码后重新执行make images构建系统会增量编译不会让你每次从头等半小时。5.4 自定义版本号的实用操作定制版本号是自编译JDK的常见需求。比如内部发布时希望java -version显示成公司内部标识可以在configure加--with-version-string17.0.0-internal重新configure之后如果构建目录结构发生变化我建议执行一次make clean再编译避免旧配置残留影响新产物。版本号定制并不会让你拿到的JDK性能更好但能有效避免内部多个版本混用时搞不清到底跑的是哪个。6. 常见问题与排查实录6.1 configure阶段的高频报错configure阶段的问题九成是环境依赖没到位。下面是我见过最多的几种情况现象原因解决办法提示找不到autoconf系统未安装autoconf用包管理器安装autoconfCannot locate a valid boot JDK未安装JDK16或路径未指定安装JDK16并指定--with-boot-jdkMissing freetype library缺少freetype开发包安装freetype开发包X11相关头文件缺失缺少图形库开发包安装libx11、libxext等开发包Compiler warnings视为错误GCC版本与构建预期不完全一致加上--disable-warnings-as-errors如果configure报错信息不够直观直接打开config.log。它记录的是完整检测过程和错误上下文往往比屏幕上的几行摘要更有用。6.2 make阶段的翻车现场make阶段最常见的翻车原因是内存不足。如果你看到编译进程被系统杀掉或者连续出现“virtual memory exhausted”类报错先把JOBS降下来make JOBS1 images如果磁盘空间不够构建过程可能报错但你看到的不一定是“disk full”而可能是某个临时文件写入失败。这时候先df -h查磁盘再用make clean清理当前构建目录。GCC版本过新或过旧也会导致编译出错。常见现象是C源码在某个模板特化或强制转换位置一直编译不过。这种情况优先确认GCC是否在支持范围内其次可以尝试加--disable-warnings-as-errors绕过警告升错误的问题。真的遇到编译器内部错误先怀疑是不是GCC自身的问题可以考虑换Clang。6.3 验证阶段遇到运行时问题自编译JDK启动时如果提示找不到libjvm.so大概率是环境变量问题。虽然自编译产物的bin/java一般会自动找相对路径的库但如果你手动拷贝了部分目录或者设置了乱七八糟的LD_LIBRARY_PATH就会遇到这种经典问题。遇到时先检查目录完整性而不是急着改环境变量。还有一个容易被误判的问题fastdebug产物跑业务应用特别慢。这是正常现象因为断言和调试日志都开着。做性能测试一定要用release构建否则数据会误导你。6.4 编译老手的一些习惯总结最后分享几个我自己经过多次编译沉淀下来的习惯不算标准答案但能帮你少走弯路。第一把configure参数记到一个文本文件里。JDK的configure参数有几十个你这次用了哪些、为什么用过了两个月再回来编另一个版本时非常容易忘。我习惯在源码目录下放一个build-command.sh里面写好完整的configure命令和注释以后直接复制执行。第二日志永远用tee存一份。compile过程几十分钟一次错误输出的滚动日志炒鸡长没有build.log基本没法回溯。虽然全量日志很占空间但值得。第三不要用sudo编译。用root或sudo会把构建产物的属主搞混之后你想清理目录、修改源码时可能遇到权限问题。我习惯单独建一个用户目录整个源码和构建都放在自己名下。第四浅克隆省时间但不要因此丢了历史。git clone --depth 1适合快速上手如果你真要看某个JVM行为的历史变更还是需要完整clone。我的做法是常用环境用浅克隆专项研究就老老实实拉全量。第五不要拿fastdebug产物去压性能也不要拿release产物去调JVM源码两者用途完全分开。自己编译JDK这件事做顺一次之后整个构建系统对你来说就是透明的。以后再遇到平台适配、补丁定制、JVM源码分析你都不会觉得它是个神秘的黑盒。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询