专栏首页古时的风筝写 Java 这么久了,来编译个 JDK 玩玩儿吧

写 Java 这么久了,来编译个 JDK 玩玩儿吧

你每天写的 Java 代码都需要 JDK 的支持,都要跑在 JVM 上,难道你就不好奇 JDK 长什么样子吗。好奇,就来编译并实现一个自己的 JDK 吧。

本次编译环境 macOS 10.12,编译的是 JDK 11 版本。

安装 OpenJDK 11

编译 OpenJDK 需要先在机器上安装 OpenJDK 10 或者 OpenJDK 11,作为 Boot JDK。 先安装 openJDK 11 编译需要,可以到 adoptopenjdk 网站去下载。

pkg 格式安装

进入页面 https://adoptopenjdk.net/index.html?variant=openjdk11&jvmVariant=hotspot 直接下载下载,然后双击就可以完成安装了。

tar.gz 格式安装

1、进入页面 https://adoptopenjdk.net/installation.html?variant=openjdk11&jvmVariant=hotspot#x64_mac-jdk 下载 tar.gz 包

2、解压

tar -xf OpenJDK11U-jdk_x64_mac_hotspot_11.0.5_10.tar.gz

解压后是一个 macOS 包,可通过右键->显示包内容查看里面的文件。

3、加入环境变量 PATH 中,当然如果你使用其他版本的 JDK 作为开发使用,请忽略这一步。

export PATH=$PWD/jdk-11.0.5+10/Contents/Home/bin:$PATH

4、macOS JDK 默认目录在/Library/Java/JavaVirtualMachines,把第 2 步解压的内容放到此目录下,之后编译的过程中会在这个目录下查找 JDK 10 或 JDK 11。

下面是我本地的目录结构,有 7 、8、11 这三个版本,开发时候还是默认使用 8 的。

安装 xcode

实际上我们需要的不是 xcode,而是 LLVM 的编译命令 clang。当然你可以单独安装 LLVM,但限于此篇是写给 Java 开发者的,安装 xcode 是最简单的版本。

我本地是很早之前安装的 xcode 8.1,编译起来是没问题的,如果你用的是比较新的版本,应该也不会出现什么问题,可以亲自试一试。

开始编译

1、下载 OpenJDK 11 源码

OpenJDK 的源码放在了网站 http://hg.openjdk.java.net/ 上,我们要下载的 JDK11 目录在 http://hg.openjdk.java.net/jdk-updates/jdk11u/

进入页面后,先点击左侧的 browse,再选择一种压缩格式下载。

当然还可以用 hg 命令 clone 到本地,使用 hg 需要安装 mercurial,如果网速不好或者不稳定,建议不要使用这种方式。

hg clone https://hg.openjdk.java.net/jdk/jdk11/

2、解压源码包

将你刚刚下载的压缩包解压,请解压到一个全英文目录下,不要使用中文,减少编译时带来的麻烦。

3、configure

进入上一步解压后的目录,执行如下命令。

sh configure --with-target-bits=64 --enable-ccache --with-jvm-variants=server  --with-boot-jdk-jvmargs="-Xlint:deprecation -Xlint:unchecked" --disable-warnings-as-errors --with-debug-level=slowdebug 2>&1 | tee configure_mac_x64.log

执行这个命令的前提是我已经将 OpenJDK 11 放到了 /Library/Java/JavaVirtualMachines目录下。

如果不放到这个目录下,也是可以的,需要额外指定参数

--with-boot-jdk=OpenJDK 目录

如果出现如下输出,说明这一步就正常了。

4、make

正式开始编译了,使用 make 命令即可。

make

首次编译会比较慢,我的是 MacBook Pro i5 8G 的那款,大概编译了 10 几分钟吧。当出现如下输出的时候,说明编译成功。

Finished building target 'default (exploded-image)' in configuration 'macosx-x86_64-normal-server-slowdebug'

编译好之后,会在当前目录出现 build 目录,进去之后,看到有个 macosx-x86_64-normal-server-slowdebug 就是最终的目录。

IDEA 中配置使用编译好的 JDK

1、打开 IDEA ,找到 File->Project Structure。

2、添加一个 JDK

3、选择上面源码编译好的 jdk

4、最后启动项目的时候指定这个 JDK 就可以了。

用 CLion 调试

1、打开 CLion ,导入项目,选择下载的源码所在位置的 src 目录。

2、配置 Debug Configurations,选择 Executable 为编译好的 java 可执行程序,在 bin 目录下,并且移除 Build 设置。

Program arguments 设置为 -version,也可以设置其他的。设置为 -version 的意思是 java -version。

3、最后在源码中打个断点,比如 jni.cpp 或 thread.cpp 中,然后点击 debug ,就可以调试啦。

打造自己的 JDK

标题说的有点儿悬,打造自己的 JDK 哪儿有那么容易,况且还确实没那个实力。这里就是介绍一种思路,比如有些时候,我们调试 Java 代码最后发现走到了 JVM 层,这种情况下,我们就跟不进去了。执行到 JVM 层之后,里面的各种变量是怎么变换的我们就不知道了。这时候,我们找到 JVM 对应的代码稍微改一下,比如加个 printf 输出一下参数值就可以清晰的看出来了。

修改 JDK 代码

我在打开的 CLion 中找到了 java.c 文件的 JavaMain(void * _args) 方法,在里面加了一行打印代码,就勉强算实现了自己的 JDK 吧(微笑脸)。

万里长征第一步嘛,别的不重要,留下脚印儿才是关键。

printf("古时的风筝 JDK \n");

重新编译修改后的源码

修改之后,在终端中进入到源码目录的根目录,然后执行 make 命令。

因为之前已经编译过了,所以再次执行 make 是进行的增量编译,所以速度很快。

好了,见证奇迹的时刻到了

我们之前已经在 IDEA 中添加了编译好的 JDK,并且指定给了一个项目。仅为测试,代码如下。

public static void main(String[] args){
    System.out.println("hello jvm");
}

当我们运行这个项目的时候,如果是平常的 JDK,会在控制台输出 hello jvm ,对不对。

可是,现在指定的不是平常的 JDK ,是被我加持过的 JDK 。

开始运行,输出的结果如下,看到没,刚刚加上的那行代码起作用了。

风筝说

真正能做到 JDK 定制开发的人并不多,我也完全没这个实力。但是每个 Java 开发者都编译一下 JDK 源码,翻一翻代码还是很有必要的。毕竟,我们每天写的代码都需要 JDK 的支持,都要跑在 JVM 上,我们就不好奇它们长成什么模样吗。

另外,这也可能为我们日常解决问题提供一种思路。有人说,最好的老师就是搜索引擎,大多数情况下是没错,但有的时候最好的方式往往就是看一眼源码。

为什么有的人解决问题的速度快,有些看似不能解决的问题放到大牛手里就能很快解决。有时候就是解决问题的维度不一样,人家是在三维的世界里,你却一直在二维的平面里转圈圈,比方说遇到程序问题,只能分析 Java 层面的问题这就是二维,进到 JDK、JVM 源码那就是进到的三维。维度高了,角度变了,解决问题的可能性和方式也就多了。这就好比三体里高等文明利用二向箔进行打击,完全不在一个体量下。

赶紧行动吧,编译一个你自己的 JDK。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JDK 13 都已经发布了,Java 8 依然是最爱

    在 JDK 版本的世界里,从来都是 Oracle 发他的新版本,我们继续用我们的老版本。三年之前用 JDK 7,后来终于升级到了 JDK 8。自从升级了没多久,...

    古时的风筝
  • 网关我选 Spring Cloud Gateway

    网关可提供请求路由与组合、协议转换、安全认证、服务鉴权、流量控制与日志监控等服务。可选的网关有不少,比如 Nginx、高性能网关 OpenResty、Linke...

    古时的风筝
  • django开发个人简易Blog——数据模型

    提到数据模型,一定要说一下MVC,MVC框架是现代web开发中最流行的开发框架,它将数据与业务逻辑分开,减小了应用之间的高度耦合。个人非常喜欢MVC开发框架,除...

    古时的风筝
  • 开发者必备的6款源码搜索引擎

    在推动技术变革上,开源运动发挥了非常显著的作用。而Linux成功地将开源转换成商务模式,给广大开源工作者带来了更大的信心和勇气。目前,开源已成为主流,在未来的几...

    hbbliyong
  • Kubenetes里pod和service绑定的实现方式

    我之前的文章 如何在Kubernetes里创建一个Nginx service介绍了如何创建一个Kubernetes pod和service,使用的方法是命令ku...

    Jerry Wang
  • SAP官网发布的react教程

    大家学习React的时候,用的是什么教程呢?Jerry当时用的阮一峰博客上的入门教程,因为React使用的JSX语法并不是所有的浏览器都支持,所以还得使用bro...

    Jerry Wang
  • SAP Cloud for Customer里的服务请求(Service Request)路由(Route)实现原理

    Configuring Ticket Routing Rules by Team or Territory:

    Jerry Wang
  • Docker更名Moby,也是无奈之举

    在上周二于德克萨斯州奥斯汀市召开的DockerCon 2017大会上,这家容器厂商宣布推出“Moby项目”,将其旗下的Docker产品(包括DockerCE与D...

    Debian社区
  • cssjshtml vue.js 双向绑定

    葫芦
  • 如何在SAP gateway系统配置路由到后台系统的OData服务路径

    看这张架构图,SAP Gateway系统也叫frontend系统,通过RFC远程调用SAP后台系统的OData服务实现。

    Jerry Wang

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动