想要深入了解JVM,就必须了解其实现机制。了解JVM实现的最好方法便是自己动手编译JDK。好了,让我们开始吧!

1.  准备工作

  • 获取OpenJDK源码

本次编译选择的是OpenJDK7u,官方源码包:https://jdk7.java.net/source.html

  • 系统需求

为了提高效率,尽量选择Linux 或 MacOS作为编译平台。本次使用Ubuntu12.04进行编译。仔细阅读源码包中README-builds.html文档,就可以构建编译环境了。

2.  配置编译环境

  • 编译依赖

OpenJDK包括虚拟机Hotsport | JDK API | JAXWS | JAXP等。需要各种编译依赖,包括C++,C的编译环境,编译Java的JDK(称为Bootstrap JDK),还有用于执行java代码的Ant脚本等等。这些依赖在Linux中都可以通过命令一次安装完成。

sudo apt-get install build-essential gawk m4 libasound2-dev libcups-dev libxrender-dev xorg-dev xutils-dev x11proto-print-dev binutils libmotif3 libmotif-dev ant

当然,也可以在命令里面加上openjdk-6-jdk,但是由于openjdk在后面的编译中出现了bug,所以还是建议大家安装Oracle jdk。注意,bootstrap JDK版本必须在6以上。

  • 环境变量

OpenJDK在编译时会读取许多环境变量,所以必须对Linux的环境变量进行配置。使用VIM编辑/etc/profile。 vim /etc/profile

具体在profile中添加的环境变量如下

export LANG=C

#BootStrap-JDK的安装路径,替换为自己bootstrap-JDK的路径

export ALT_BOOTDIR=/usr/lib/jvm/java--openjdk-i386

#同上,我之前使用的是openjdk编译的,后面运行hotspot时出现问题替换为oracleJDK,读者可以直接替换为OracleJDK

export ALT_JDK_IMPORT_PATH=/usr/lib/jvm/java--openjdk-i386

#要编译的内容,读者可以根据需要自行选择

export BUILD_LANGTOOLS=true

#export BUILD_JAXWS=false

#export BUILD_JAXP=false

#export BUILD_CORBA=false

export BUILD_HOTSPOT=true

export BUILD_JDK=true

export SKIP_COMPARE_IMAGES=true

BUILD_DEPLOY=false

BUILD_INSTALL=false

#编译结果存放的路径,建议存放在openjdk源码中build文件夹

export ALT_OUTPUTDIR=/usr/dev/jvm/openjdk/build

export ALLOW_DOWNLOADS=true

#这两个环境变量需要去掉,不然会出问题

unset JAVA_HOME

unset CLASSPATH

添加完成后,进入openjdk源码路径,通过make sanity命令来检查设置是否正确,如果正确,会返回Sanity check passed。

3.  开始编译OpenJDK

  • 使用make命令

在openjdk目录下,输入make命令,正常情况下大概需要30分钟左右,具体速度根据机器性能决定。编译正常结束后,会出现日志清单展示内容,如图

  • 查看编译结果

进入build/j2sdk-image目录下,查看整个JDK的编译结果,运行java –version

4.  运行HotSpot

  • 编辑env.sh

虚拟机的输出结果存放在build/hotspot/outputdir/linux_i486_compiler2路径下,如图

使用VIM编辑product目录下的env.sh

我们发现里面已经有了JAVA_HOME CLASSPATH HOTSPOT_BUILD_USER等环境变量,我们还需要添加一个LD_LIBRARY_PATH,否则在运行时还会出现问题。

LD_LIBRARY_PATH=.:${JAVA_HOME}/jre/lib/i386/native_threads:${JAVA_HOME}/jre/lib/i386:

export LD_LIBRARY_PATH
  • 执行命令启动JVM

使用如下命令,启动虚拟机,输出版本号

. ./env.sh

./gamma –vesion

成功结果如图

至此成功编译运行OpenJDK7,下面讲讲过程中遇到的问题。

5.  编译运行过程中可能会遇到的问题

  • OpenJDK6.0的bug

使用OpenJDK6.0作为bootstrap JDK的话,在编译及运行过程中可能会出现类似于这样的错误,运行./gamma时也可能出现,这类错误都属于OpenJDK-6中的bug

relocation error: /usr/lib/jvm/java--openjdk-i386/jre/lib/i386/libjava.so: symbol JVM_FindClassFromCaller, version SUNWprivate_1. not defined in file libjvm.so with link time reference

网上提供的一种解决方案是通过find –name 'CurrencyData.properties' 找到CurrencyData文件,把文件中的时间全部修改为10年以内。然而我尝试了这种方法并不能解决问题,于是尝试把Bootstrap JDK由openjdk-6更换为OracleJDK6,终于解决问题。

  • 未取消掉JAVA_HOME变量

如果没有在环境变量中添加unset JAVA_HOME,make Sanity时会出现以下错误

ERROR: Your JAVA_HOME environment variable is set. This will most likely cause the build to fail. Please unset it and start your build again.

Exiting because of the above error(s).

make: *** [post-sanity] Error 

在/etc/profile中添加unset JAVA_HOME以解决问题

还有许多在编译过程中遇到的问题,在前文中已经进行弥补和完善,相信大家按照这些步骤进行编译,会省去不少麻烦。

6.  总结

通过自己动手编译OpenJDK-7的源码,我们可以深入了解JVM的编译环境以及运行过程。通过解决编译过程中遇到的问题,为后续对JVM的深入探索打下了良好的基础。在此基础上,我们还可以通过NetBeans对Hotspot进行运行和调试,进一步了解JVM源码的结构与细节。

走进JVM之一 自己编译openjdk源码的更多相关文章

  1. 编译openjdk源码

    http://www.cnblogs.com/ACFLOOD/p/5528035.html

  2. ubuntu18.04.2下编译openjdk9源码

    最近在看<深入理解Java虚拟机 第二版>这本书,上面有关于自己编译OpenJDK源码的内容.自己根据书里的指示去操作,花了三天的时间,重装了好几次Ubuntu(还不知道快照这个功能,好傻 ...

  3. 转-OpenJDK源码阅读导航跟编译

    OpenJDK源码阅读导航 OpenJDK源码阅读导航 博客分类: Virtual Machine HotSpot VM Java OpenJDK openjdk 这是链接帖.主体内容都在各链接中.  ...

  4. OpenJDK源码研究笔记(十一):浅析Javac编译过程中的抽象语法树(IfElse,While,Switch等语句的抽象和封装)

    浅析OpenJDK源码编译器Javac的语法树包com.sun.source.tree. 抽象语法树,是编译原理中的经典问题,有点难,本文只是随便写写. 0.赋值语句 public interface ...

  5. OpenJDK源码研究笔记(十三):Javac编译过程中的上下文容器(Context)、单例(Singleton)和延迟创建(LazyCreation)3种模式

    在阅读Javac源码的过程中,发现一个上下文对象Context. 这个对象用来确保一次编译过程中的用到的类都只有一个实例,即实现我们经常提到的"单例模式". 今天,特意对这个上下文 ...

  6. 第一篇: openJDK源码编译安装--mac版本

    1.为什么要编译JDK 想要一探JDK内部的实现机制,最便捷的路径之一就是自己编译一套JDK,通过阅读和跟踪调试JDK源码去了解Java技术体系的原理,虽然门槛高一点,但肯定比阅读各种书籍,文章,博客 ...

  7. 在Ubuntu-14.04.3配置并成功编译Android6_r1源码

    折腾了一周,终于把Android6_r1的源码编译成功.先上图,这是在ubuntu中运行的Android模拟器: 由于我是在win8中安装虚拟机VMware,然后在虚拟机中安装Ubuntu进行编译,所 ...

  8. 一次编译Android源码实验

    注意,本文只供参考,是老文章 1.必要的软件环境 sudo apt-get install build-essential sudo apt-get install make sudo apt-get ...

  9. [Android Pro] 自己动手编译Android源码(超详细)

    cp from : https://www.jianshu.com/p/367f0886e62b 在Android Studio代码调试一文中,简单的介绍了代码调试的一些技巧.现在我们来谈谈andro ...

随机推荐

  1. 《移山之道》Reading Task

    老师布置的阅读任务虽然是附加的作业,但是对我来说是个很好的学习机会.软件工程主要是对工程的开发进行学习,毕竟在学校老师教了那么多的知识,我们课下做了那么多的练习并没有提高我们做一个工程的能力.一个项目 ...

  2. Notes of Daily Scrum Meeting(12.25)

    今天在学姐的帮助下,我们终于把网络连接的部分连通了,这对我们是一个很大的鼓舞,也找到了前期 连不通的问题在哪里,这让我们重新有了进行下去的勇气和决心,我们会在最后这几天把前端和后端结合, 做出我们最后 ...

  3. Daily scrum 12.21

    今天ui组反映了一个数据库数据类型的问题,开发人员在完成任务后再去处理. Member Today’s task 林豪森 与学霸其他小组交流,处理整合问题 宋天舒 修复数据库问题 张迎春 修复数据库问 ...

  4. linux内核分析第四次实验

    实验步骤: 使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用.本次实验中我使用第20号系统调用getpid()函数,用于取得进程识别码. C代码(getpid.c): #include ...

  5. 牛客OI周赛7-提高组

    https://ac.nowcoder.com/acm/contest/371#question A.小睿睿的等式 #include <bits/stdc++.h> using names ...

  6. HDU 2075 A|B?

    http://acm.hdu.edu.cn/showproblem.php?pid=2075 Problem Description 正整数A是否能被正整数B整除,不知道为什么xhd会研究这个问题,来 ...

  7. 使用telnet模拟http请求

    HTTP 首先我们需要知道http报文是由一系列的字符串组成的.然后我们来了解具体的相关事项. 方法 HTTP支持几种不同形式的请求命令,这些命令就被称为HTTP方法.每个HTTP请求报文都包含一个方 ...

  8. 用IntelliJ IDEA编译,编译之后提示 无效的标记: -release

    软件版本:ideaIU-2016.3.2 JDK:jdk-9.0.4_windows-x64_bin 开始的时候建立一个maven项目,发现编译的时候提示[无效的标记: -release],以为是项目 ...

  9. CentOS7 完整安装后创建私有的yum仓库

    1. 安装 CentOS7 安装的包比较全,应用可以直接用. 2. 第一步创建 yum 包的存放路径 mkdir -p /var/www/html/ 3. 创建私有仓库 createrepo -v / ...

  10. intval()和int()

    int intval ( mixed $var [, int $base ] )    通过使用特定的进制转换(默认是十进制),参数base表示进制,只有当var是字符串时,base才会有意义,表示按 ...