编译虚拟机jvm——openjdk的编译
java只所以被推广,实际上很大原因是因为本身是跨平台的,很大作用是因为虚拟机的关系。
一般情况下开发人员不需要关注虚拟机内部实现就可以日常开发了,但是有时候涉及到性能的时候就需要了解虚拟机的实现机制了。
那么今天写的内容更多的是关于编译一套自己的虚拟机,为日后了解虚拟机底层原理铺铺路。
编译虚拟机可能会遇到很多坑,也很花费时间。也因大家的环境的差异,可能遇到的问题都不一致。
我只能说把自己遇到的问题都列出来,权当抛砖引玉了。
1首先我们应该下载openjdk的源码,这个openjdk实际上是有一个版本历史的,大家可以去了解一下,
然后这里面的源码内容和oracle jdk内容大部分都是一致的,少数内容不一样。
我这里下载的openjdk 源码是openjdk-7u75-src-b13-18_dec_2014.zip,每个人的版本可能不太一样,不过 是openjdk的源码就行。
2除了上面的东西要准备,其实还要准备一个oracle的jdk,这个jdk我用的是jdk-6u32-linux-x64.bin。
3然后是在linux上先准备好各种依赖,这些依赖获得方式待会儿会讲,另外要讲的是,我这里的linux系统
是ubuntu的 16.04LTS 64位的,所以之前的东西也最好都准备64位的。
东西都准备好了,现在我们开干!!!!
1如果之前你设置了java_home或者classpath环境变量,请先注释掉。
2将openjdk-7u75-src-b13-18_dec_2014.zip解压后得到openjdk文件夹,我们把他放到/usr下。
3执行jdk-6u32-linux-x64.bin,得到jdk1.6.0_32文件夹,我们讲这个文件夹放到/usr/java下。
4输入vim /etc/profile,在最后加入如下内容:
export LANG=C #BootStrap-JDK的安装路径,替换为自己bootstrap-JDK的路径 export ALT_BOOTDIR=/usr/java/jdk1..0_32 #同上,我之前使用的是openjdk编译的,后面运行hotspot时出现问题替换为oracleJDK,读者可以直接替换为OracleJDK export ALT_JDK_IMPORT_PATH=/usr/java/jdk1..0_32 #规定几个线程来执行这个脚本
export HOTSPOT_BUILD_JOBS=
export ALT_PARALLEL_COMPILE_JOBS= #要编译的内容,读者可以根据需要自行选择 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/openjdk/build export ALLOW_DOWNLOADS=true #这两个环境变量需要去掉,不然会出问题 unset JAVA_HOME unset CLASSPATH make >& | tee $ALT_OUTPUTDIR/build.log
注意的是需要source /etc/profile,以更新配置。但是输入后会马上跑起来,但是现在是不会成功的,因为依赖那些还没弄好。直接马上接着按ctrl+c以暂停。
5在终端执行一些命令以安装必要的依赖,命令如下:
sudo apt-get install build-essential gawk m4 libasound2-dev libcups2-dev libxrender-dev xorg-dev xutils-dev x11proto-print-dev binutils libmotif-common ant
有些地方还安装了openjdk-6-jdk,其实这里不安装这个更好,我们用的是oracle的jdk来编译我们的openjdk源码,不建议用openjdk-6-jdk来编译openjdk源码,那也正是我build.sh脚本里面指向的jdk地址是export ALT_BOOTDIR=/usr/java/jdk1.6.0_32的原因。
6现在我们到/usr/openjdk目录去执行make sanity命令,检查是否配置都没问题了。如果没有问题就会显示

7万事具备,只欠东风,输入make,开始编译,编译出的东西会生成在/usr/openjdk/build目录。
流程就是这样的,不过期间会出现一些问题,根据他报的错我们要修正一些错误,修正之后再继续make命令接着编译。
下面是我遇到的一些错误和解决办法。
1>
echo "*** This OS is not supported:" `uname -a`; exit 1;
openjdk/hotspot/make/linux/Makefile:240: recipe for target 'check_os_version' failed
解决:
将/openjdk/hotspot/make/linux/Makefile中的check_os_version下面三行注释掉
check_os_version:
#ifeq ($(DISABLE_HOTSPOT_OS_VERSION_CHECK)$(EMPTY_IF_NOT_SUPPORTED),)
# $(QUIETLY) >&2 echo "*** This OS is not supported:" `uname -a`; exit 1;
#endif
2>
undefined reference to `void G1SATBCardTableModRefBS::write_ref_array_pre_work<oopDesc*>(oopDesc**, int)'
解决:将hotspot/src/share/vm/gc_implementation/g1里的g1SATBCardTableModRefBS.cpp
template <class T> void G1SATBCardTableModRefBS::write_ref_array_pre_work(T* dst, int count) { if (!JavaThread::satb_mark_queue_set().is_active()) return; T* elem_ptr = dst; for (int i = 0; i < count; i++, elem_ptr++) { T heap_oop = oopDesc::load_heap_oop(elem_ptr); if (!oopDesc::is_null(heap_oop)) { enqueue(oopDesc::decode_heap_oop_not_null(heap_oop)); } } }内容下加上如下
//2017-10-19 Vicent_Chen added void G1SATBCardTableModRefBS::write_ref_array_pre(oop* dst, int count, bool dest_uninitialized) { if (!dest_uninitialized) { write_ref_array_pre_work(dst, count); } } void G1SATBCardTableModRefBS::write_ref_array_pre(narrowOop* dst, int count, bool dest_uninitialized) { if (!dest_uninitialized) { write_ref_array_pre_work(dst, count); } } //2017-10-19 Vicent_Chen added
将hotspot/src/share/vm/gc_implementation/g1里的g1SATBCardTableModRefBS.hpp如下部分
virtual void write_ref_array_pre(oop* dst, int count, bool dest_uninitialized) { if (!dest_uninitialized) { write_ref_array_pre_work(dst, count); } } virtual void write_ref_array_pre(narrowOop* dst, int count, bool dest_uninitialized) { if (!dest_uninitialized) { write_ref_array_pre_work(dst, count); } }
注释掉,然后在加入virtual void write_ref_array_pre(oop* dst, int count, bool dest_uninitialized); virtual void write_ref_array_pre(narrowOop* dst, int count, bool dest_unintialized);
3>
Error: time is more than 10 years from present: 1136059200000
解决:
openjdk/jdk/src/share/classes/java/util/CurrencyData.properties文件中以下时间改成10年以内
AZ=AZM;2005-12-31-20-00-00;AZN
MZ=MZM;2006-06-30-22-00-00;MZN
RO=ROL;2005-06-30-21-00-00;RON
TR=TRL;2004-12-31-22-00-00;TRY
VE=VEB;2008-01-01-04-00-00;VEF
4>之后可能在编译RMIServerImpl_Stub.class的时候,很可能是内存不够了,因为我通过系统监视器观察得到这段时间内内存在暴增,具体原因也不知道,但是我连续几次在make命令重新来的时候,到最后一次
又成功了。所以遇到这种情况这种情况可以多次重来。最后一次内存就没有暴增了。
编译成功就是如下的样子了:

之后在build文件夹内就能找到你编译好的jdk。
谢谢大家,有什么不明了的可以向我提问。
编译虚拟机jvm——openjdk的编译的更多相关文章
- 深入解析java虚拟机-jvm运行机制
转自oschina 一:JVM基础概念 JVM(Java虚拟机)一种用于计算设备的规范,可用不同的方式(软件或硬件)加以实现.编译虚拟机的指令集与编译微处理器的指令集非常类似.Java虚拟机包括一套字 ...
- 走进JVM之一 自己编译openjdk源码
想要深入了解JVM,就必须了解其实现机制.了解JVM实现的最好方法便是自己动手编译JDK.好了,让我们开始吧! 1. 准备工作 获取OpenJDK源码 本次编译选择的是OpenJDK7u,官方源码包 ...
- JAVA 文件编译执行与虚拟机(JVM)简单介绍
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytpo3 java程序的内存分配 JAVA 文件编译执行与虚拟机(JVM)介绍 ...
- openjdk 完全编译指南
从openjdk.java.net下载openjdk的软件包,你就获得了所有相关的源码. 强烈建议首先仔细看懂 README-builds.html 指南. 在执行 make all 之前,首先要 执 ...
- JVM源码分析-JVM源码编译与调试
要分析JVM的源码,结合资料直接阅读是一种方式,但是遇到一些想不通的场景,必须要结合调试,查看执行路径以及参数具体的值,才能搞得明白.所以我们先来把JVM的源码进行编译,并能够使用GDB进行调试. 编 ...
- JVM(十三):后端编译优化
JVM(十三):后端编译优化 在 JVM(一):源文件的转变 中我们介绍了 Java 中的前端优化,即将 Java 源代码转换为字节码文件.在本文中,我们将介绍字节码文件如何转换为本地机器码,并如何对 ...
- 《深入理解JAVA虚拟机》-自己动手编译JDK
环境 Ubuntu12.4-http://mirrors.163.com/ubuntu-releases/12.04/ --需要安装纯英文版,避免中文引起不必要的麻烦 OpenJDK7-https:/ ...
- JVM JIT动态编译
一.概述 1.1 基本概念 a. 动态编译(dynamic compilation)指的是"在运行时进行编译":与之相对的是事前编译(ahead-of-time compilati ...
- 【Java】实战Java虚拟机之五“开启JIT编译”
今天开始实战Java虚拟机之五“开启JIT编译” 总计有5个系列 实战Java虚拟机之一“堆溢出处理” 实战Java虚拟机之二“虚拟机的工作模式” 实战Java虚拟机之三“G1的新生代GC” 实战Ja ...
随机推荐
- 调试 ms 源代码
如果需要调试 WPF 源代码或框架源代码,那么需要使用 DotPeek. 首先需要下载 dotPeek ,可以到官网下载 dotPeek: Free .NET Decompiler & Ass ...
- OpenWRT (RT5350) 使能两个串口
OpenWRT(RT5350) 默认使能一个串口(uartlite) ,当做console口了,另外一个串口(uartf)与gpio复用. 在查找资料的过程中,发现在新的内核中使用到了设备树(devi ...
- 使用vim编写hexo文档,并用ultisnips/snipmates/snippets插件补全
作为一个vim使用者,编写markdown文档时若不能用vim这怎么能受的了! 下面是我编写markdown的时候用到的插件 Plugin 'Markdown'Plugin 'Markdown-syn ...
- [oracle 使用(2)] Oracle的简单使用
1:oracle的服务 oracleservice + sid # 数据库服务 oracleoradb10g_home1listener # 数据库的监听服务. 2:启动本机数据库: 启动oracle ...
- yii2之数据验证
一.场景 什么情况下需要使用场景呢?当一个模型需要在不同情境中使用时,若不同情境下需要的数据表字段和数据验证规则有所 不同,则需要定义多个场景来区分不同使用情境.例如,用户注册的时候需要填写email ...
- aapt不是内部命令
解决方法:在E:\sdk\build-tools\目录下的任意文件夹下查找aapt,复制到E:\sdk\platform-tools,具体盘符是情况而定,如果还不行,尝试配置环境变量!
- 进程,线程,GIL,Python多线程,生产者消费者模型都是什么鬼
1. 操作系统基本知识,进程,线程 CPU是计算机的核心,承担了所有的计算任务: 操作系统是计算机的管理者,它负责任务的调度.资源的分配和管理,统领整个计算机硬件:那么操作系统是如何进行任务调度的呢? ...
- 利用cookies+requests包登陆微博,使用xpath抓取目标用户的用户信息、微博以及对应评论
本文目的:介绍如何抓取微博内容,利用requests包+cookies实现登陆微博,lxml包的xpath语法解析网页,抓取目标内容. 所需python包:requests.lxml 皆使用pip安装 ...
- Python学习之二:Python 与 C 区别
引自http://www.lxway.com/181844.htm 从开始看Python到现在也有半个多月了,前后看了Python核心编程和Dive into Python两本书.话说半个月看两本,是 ...
- 前后端分离跨服务器文件上传-Java SpringMVC版
近来工作上不上特别忙,加上对后台java了解一点,所以就抽时间,写了一个java版本的前后端分离的跨服务器文件上传功能,包括前后端代码. 一.Tomcat服务器部分 1.Tomcat服务器 单独复制一 ...