深刻理解JVM虚拟机-Ubuntu中安装openJDK

最近利用闲暇时间看了看《深刻理解java虚拟机》来提升自身得知识储备,再这里准备将读书学习到得知识和我的的心得记录下来。首先调整好本身的心态,不要浮躁,由于编译阶段会无限踩坑。html

1.安装VMware和Ubuntu系统

这本书得里用得是Ubuntu系统,在这里我为了少踩坑放弃了以前一直使用得Centos7改成使用Ubuntu。VMware和Ubuntu系统安装比较简单,这里我也是参照一篇博客安装得,按照步骤安装就能够了,这里我用的乌班图版本为ubuntu-14.04.6-desktop-amd64,这里没有使用跟本书写着用的Ubuntu-10版本的,由于10版本的更新源实在太难找了。
VMware上安装乌班图系统参照此篇博客
固然,这里面仍是略微有些坑。java

  1. 安装好系统后只有用户的帐号密码设置,可是你在不少操做的时候都会显示权限不足,这时候你须要修改root帐户的密码,使用命令sudo passwd(打开命令行操做界面快捷键为Ctrl+Alt+T),而后输入你要设置的root密码就能够了。
  2. VMware Tools安装。乌班图系统安装好后你会发如今WMware的界面上显示的窗口很是小,这时候你须要在系统上装上WMware tools。
    点击WMware控制台上的虚拟机-安装WMware Tools后,会在你的乌班图系统中装载,右键将压缩包提取到桌面,右键解压好的文件夹在终端打开,执行命令sudo ./vmware-install.pl,第一个提示输入yes后一路回车,安装好以后重启就能够了。

2.编译openJDK

2.1 ANT等编译工具下载

首先打开终端,输入指令:node

#依赖脚本
sudo apt-get install build-essential gawk m4 libasound2-dev libcups2-dev libxrender-dev xorg-dev xutils-dev x11proto-print-dev binutils libmotif3 libmotif-dev libxt-dev ant libxtst-dev
#opendjdk7的依赖
sudo apt-get build-dep openjdk-7
复制代码

这一步有可能会报错 linux

错误图片
这时须要先执行 sudo apt-get update,再执行上面的命令就能够了。

2.2 手动下载包

  1. openjdk7的源包 下载地址,下载后进行解压便可。
  2. oracle的jdk6的源包,因为ubuntu系统自带了openjdk8,而我要用oracleJDK1.7,因此须要先卸载系统自带的openjdk,卸载以下:
若是安装了OpenJDK,可用以下方法所有卸载:
$sudo apt-get purge openjdk*
复制代码

卸载后去oracle官网下载jdk,我下载的是jdk7u80。下载完成后传输到Ubuntu中,放入事先建立好的文件夹,个人openjdk和jdk都是放在/home/java路径下,而后进行解压,解压后须要配置一下jdk的环境配置。输入sudo gedit ~/.bashrc,新增:程序员

export JAVA_HOME=/home/java/jdk1.7.0_80
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$JAVA_HOME/bin:$PATH
复制代码

最后使配置生效:ubuntu

source ~/.bashrc
复制代码

2.3 配置ubuntu的JDK和JRE的位置

$ sudo update-alternatives --install "/usr/bin/java" "java" "/home/java/jdk/jdk1.7.0_80/bin/java" 1
$ sudo update-alternatives --install "/usr/bin/javac" "javac" "/home/java/jdk/jdk1.7.0_80/bin/javac" 1
$ sudo update-alternatives --install "/usr/bin/javaws" "javaws" "/home/java/jdk/jdk1.7.0_80/bin/javaws" 1
复制代码

2.4 配置Oracle为系统默认JDK/JRE

$ sudo update-alternatives --set java /home/java/jdk/jdk1.7.0_80/bin/java
$ sudo update-alternatives --set javac /home/java/jdk/jdk1.7.0_80/bin/javac
$ sudo update-alternatives --set javaws /home/java/jdk/jdk1.7.0_80/bin/javaws
复制代码

3. build.sh文件的配置及编译

再解压好的openjdk文件夹中新建一个build.sh,将配置写入。此处没有采用本书的作法,但方法都同样,只须要将配置放入/etc/profile中,而后source /etc/profile便可。浏览器

# 语言选项,必须设置,不然编译好后会出现一个 HashTable 的 NPE错
export LANG=C
 
# Bootstrap JDK 解压路径,必须设置
export ALT_BOOTDIR=/home/java/jdk1.7.0_80
 
# 容许自动下载
export ALLOW_DOWNLOADS=true
 
# 并行编译线程数
export HOTSPOT_BUILD_JOBS=4
export ALT_PARALLEL_COMPILE_JOBS=4
 
# 比较本次 build 出来的映像与先前版本的差别,对咱们没有意义
# 必须设置为 false,不然 sanity 检查为报缺乏先前版本 JDK 的映像的错误提示
export SKIP_COMPARE_IMAGE=false
 
# 使用预编译头文件,不加这个编译会变慢
export USE_PRECOMPILED_HEADER=true
 
# 要编译的内容 这里咱们全编译其实只要前三个就能够了自行注释
export BUILD_LANGTOOLS=true
export BUILD_HOTSPOT=true
export BUILD_JDK=true
#export BUILD_JAXWS=true
#export BUILD_JAXP=true
#export BUILD_CORBA=true
 
# 要编译的版本 
# export SKIP_DEBUG_BUILD=false
# export SKIP_FASTDEBUG_BUILD=true
# export DEBUG_NAME=debug
 
# 把它设置为 false 能够避开 javaws 和浏览器 Java 插件之类的部分的 build
BUILD_DEPLOY=false
 
# 把它设置为 false 就不会 build 出安装包,由于安装包里有奇怪的依赖
# 但即便不 build 出它也能获得完整的 JDK 映像,因此仍是别 build
BUILD_INSTALL=false
 
# 编译结果所存放的路径
export ALT_OUTPUTDIR=/home/java/openjdk/build

export CFLAGS="-Wno-error"
export CXXFLAGS="-Wno-error"
 
# 这两个环境变量必须去掉,否则会发生奇怪的事情
# Makefile 检查到这两个变量就会提示警告
unset JAVA_HOME
unset CLASSPATH

make 2>&1 | tee $ALT_OUTPUTDIR/build.log
复制代码

而后赋予build.sh权限并运行,以下:bash

chmod 755 build.sh
#此命令是直接启动程序进行编译
./build.sh
复制代码

4. 踩坑阶段(WTFK)

好了,轻松愉快的阅读和复制粘贴工做结束,下面就是最开心的踩坑阶段,调整好本身的心情,打开百度和Google,准备开始一场烧脑的网络冲浪吧。网络

4.1 echo “* This OS is not supported:” uname -a; exit 1

* This OS is not supported: Linux pgc-virtual-machine 3.11.0-12-generic #19-Ubuntu SMP Wed Oct 9 16:12:00 UTC 2013 i686 i686 i686 GNU/Linux 
2.3 ERROR: echo “* This OS is not supported:” ‘uname -a‘; exit 1; 
复制代码

这须要注释掉hotspot/make/linux/Makefile里面的checkOS。oracle

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

也能够最好的办法是在make参数后面添加 :
DISABLE_HOTSPOT_OS_VERSION_CHECK=OK
复制代码

4.2 BUILD FAILED

/home/pgc/Downloads/openjdk/build/jaxws/build/xml_generated/build-drop-jaf_src.xml:96: Redirection detected from https to http. Protocol switch unsafe, not allowed. 
复制代码

在这个build-drop-jaf_src.xml的96行中获取包下载的地址失效或有问题,就会致使改问题发生,这时你须要把那些包本身下载,主要是jdk7-jaf-2010_08_19.zip这个包下载不了。
须要本身下载依赖的jaxp、jaf、jaxws
jaxp145_01.zip
jdk7-jaxws2_2_4-b03-2011_05_27.zip
jdk7-jaf-2010_08_19.zip
包下载好后进入openjdk目录,建立drop文件夹,而后,把这下载到的三个包放到drop文件夹中。再执行:

export ALT_DROPS_DIR=/home/java/openjdk/openjdk/drop
复制代码

上面的路径须要根据本身的状况进行修改。

4.3 .ed.hpp:36

/home/pgc/Downloads/openjdk/hotspot/src/share/vm/runtime/interfaceSupport.hpp:430:0: error: “__LEAF” redefined [-Werror] 
#define __LEAF(result_type, header) \ 
^ 
![](https://user-gold-cdn.xitu.io/2019/3/25/169b54f02337c7c8?w=800&h=154&f=jpeg&s=23337)
In file included from /usr/include/features.h:374:0, 
复制代码

这是cdefs.h中定义的宏“LEAF”与interfaceSupport.hpp冲突。能够在interfaceSupport.hpp中增长一个“#undef LEAF”语句来解决冲突,interfaceSupport.hpp的文件地址在错误日志中找到,或者可使用find命令来进行查找。

// LEAF routines do not lock, GC or throw exceptions
#ifdef __LEAF
#undef __LEAF
#define __LEAF(result_type, header) \
TRACE_CALL(result_type, header) \
debug_only(NoHandleMark __hm;) \
/* begin of body */
#endif 
复制代码

4.4 error: converting ‘false’ to pointer type ‘methodOop’

修改/openjdk/hotspot/src/share/vm/oops/constantPoolOop.cpp 第272行 return false改成return (methodOop)false; 或者 return NULL。

4.5 error: converting ‘false’ to pointer type ‘Node*

修改openjdk/hotspot/src/share/vm/opto/loopnode.cpp: 第896行 return false改成return (Node*)false; 或者 return NULL;

4.6 ERROR gcc: error: unrecognized command line option ‘-mimpure-text’

这个-mimpure-text是gcc给Solaris的编译选项,因此注释掉或删掉便可。 文件在./jdk/make/common/shared/Compiler-gcc.gmk

4.7 Error: time is more than 10 years from present: 1136059200000

修改CurrencyData.properties(路径:jdk/src/share/classes/java/util/CurrencyData.properties)

修改108行
AZ=AZM;2018-12-31-20-00-00;AZN
修改381行
MZ=MZM;2018-06-30-22-00-00;MZN
修改443行
RO=ROL;20189-06-30-21-00-00;RON
修改535行
TR=TRL;2018-12-31-22-00-00;TRY
修改561行
VE=VEB;2018-01-01-04-00-00;VEF
复制代码

上面的行数有可能有略微误差,找到行数的附近而后根据关键字查找就能够。

4.8 collect2: error: ld returned 1 exit status

make[5]: * [/home/pgc/Downloads/openjdk/build/lib/i386/libjsoundalsa.so] Error 1
make[5]: Leaving directory `/home/pgc/Downloads/openjdk/jdk/make/javax/sound/jsoundalsa’
make[4]: * [build] Error 1 
复制代码

遇到和”javax/sound/jsoundalsa”相关的一个错误,须要修改openjdk/jdk/make/javax/sound/jsoundalsa目录下的Makefile文件,找到 LDFLAGS += -lasound 修改成 OTHER_LDLIBS += -lasound

4.9 ./test_gamma错误

这须要去掉或者注释掉hotspot/make/linux/Makefile 文件中全部包含test_gamma的整行!!!必定要是整行!

5 总结

以上的问题应该还不是编译openjdk全部的坑,可能有些问题我尚未遇到,但这些坑就已经让我搞了三天的时间才搞定,若是遇到其余比较奇葩的坑,那只能自行baidu和Google了,最终顺利的话静静等待10分钟左右(依每人各电脑性能不一样,时间可能不同)的漫长等待,最终就编译好了,编译完成后会打印一下信息。


如此,就大功告成了。

6 编译HotSpot

jdk编译完成后须要编译HotSpot,下面来一段HotSpot的介绍

提起HotSpot VM,相信全部Java程序员都知道,它是Sun JDK和OpenJDK中所带的虚拟机,也是目前使用范围最广的Java虚拟机。
但不必定全部人都知道的是,这个目前看起来“血统纯正”的虚拟机在最初并不是由Sun公司开发,而是由一家名为“Longview Technologies”的小公司设计的;
甚至这个虚拟机最初并不是是为Java语言而开发的,它来源于Strongtalk VM,
而这款虚拟机中至关多的技术又是来源于一款支持Self语言实现“达到C语言50%以上的执行效率”的目标而设计的虚拟机,
Sun公司注意到了这款虚拟机在JIT编译上有许多优秀的理念和实际效果,在1997年收购了Longview Technologies公司,从而得到了HotSpot VM。

HotSpot VM既继承了Sun以前两款商用虚拟机的优势(如前面提到的准确式内存管理),也有许多本身新的技术优点,
如它名称中的HotSpot指的就是它的热点代码探测技术(其实两个VM基本上是同时期的独立产品,HotSpot还稍早一些,HotSpot一开始就是准确式GC,
而Exact VM之中也有与HotSpot几乎同样的热点探测。
为了Exact VM和HotSpot VM哪一个成为Sun主要支持的VM产品,在Sun公司内部还有过争论,HotSpot战胜Exact并不能算技术上的胜利),
HotSpot VM的热点代码探测能力能够经过执行计数器找出最具备编译价值的代码,而后通知JIT编译器以方法为单位进行编译。
若是一个方法被频繁调用,或方法中有效循环次数不少,将会分别触发标准编译和OSR(栈上替换)编译动做。
经过编译器与解释器恰当地协同工做,能够在最优化的程序响应时间与最佳执行性能中取得平衡,并且无须等待本地代码输出才能执行程序,
即时编译的时间压力也相对减少,这样有助于引入更多的代码优化技术,输出质量更高的本地代码。

在2006年的JavaOne大会上,Sun公司宣布最终会把Java开源,并在随后的一年,陆续将JDK的各个部分(其中固然也包括了HotSpot VM)在GPL协议下公开了源码,
并在此基础上创建了OpenJDK。这样,HotSpot VM便成为了Sun JDK和OpenJDK两个实现极度接近的JDK项目的共同虚拟机。

在2008年和2009年,Oracle公司分别收购了BEA公司和Sun公司,这样Oracle就同时拥有了两款优秀的Java虚拟机:JRockit VM和HotSpot VM。
Oracle公司宣布在不久的未来(大约应在发布JDK 8的时候)会完成这两款虚拟机的整合工做,使之优点互补。
整合的方式大体上是在HotSpot的基础上,移植JRockit的优秀特性,譬如使用JRockit的垃圾回收器与MissionControl服务,
使用HotSpot的JIT编译器与混合的运行时系统。
复制代码

废话很少少,盘他。 首先按照书上步骤是进入编译输出目录,./build/j2sdk-image中,说里面有一个gamma的运行文件,恕我眼拙,找了半天只看到了test_gamma,这是什么鬼?阉割版?好吧,按照书上继续来,进行env.sh的配置,但我发现env.sh里面已经配置好了,emmmmm...........好智能,下一步把,运行./test_gamma -version,发现报错了,果真是阉割版靠不住。通过一番百度和google以后发现,原来还要编译HotSpot,好吧,看来我对书上讲的还不是特别理解。 ####6.1 编译 编译HotSpot很是简单,将刚刚建立的build.sh复制一份到/openjdk/hotspot/make中,若是是64位系统须要加上export ARCH_DATA_MODEL=64,不然回报错,而后改一下编译后的输出路径,若是都放到build中比较难找,因此我再openjdk目录下新建了一个hotbuild目录做为输出目录,最后直接运行就能够了。 执行成功后,修改env.sh,若是有就不用添加,没有添加下面两行

LD_LIBRART_PATH=.:{JAVA_HOME}/jre/lib/amd64/native_threads:%{JAVA_HOME}/jre/lib/amd64:
export LD_LIBRART_PATH
复制代码

而后运行source ./env.sh使配置生效,最后找到正版的gamma,执行./gamma -version,正确会输出一下日志。

6.2 问题(OMG)

若是有人按照个人步骤作很是完美的成功了,那么恭喜你。
在上一步./gamma -version这一步我遇到了一个问题,忘记截图了,大体的意思就是在$JAVA_HOME/jre/lib/amd64这个里面找不到东西(emmm...大概就是这个意思,原谅我比较low的英文水平)。这时候就须要反思一下前面的步骤,这时我忽然想起了书上的一句话,大概意思时”将/build/j2sdk-image中的文件复制到JAVA_HOME路径下就能够做为完整的JDK使用“,那么咱们前面的JAVA_HOME路径指向的是Oracle JDK,是否是这个地方出了问题。so,我将JAVA_HOME路径下的全部文件删除,而后将j2sdk-image中的文件都复制过去,而后运行./gamma -version,果真就成功了。

7 安装netBeans

搞完上面两步,距离成功只剩一点点了,最后来下载安装netBeans,直接官网下载就能够,我安装的是8.0版本的,要选择支持C/C++开发的那个版本。 安装成功后打开netBeans,新建项目。选择基于现有源代码的C/C++项目。

下一步,指定文件夹 /home/java/openjdk/hotspot,选择定制,下一步。
选择Makefile路径,在hotspot/make中,下一步。

这里须要修改构建命令(其中ALT_BOOTDIR为你编译后的jdk路径):

${MAKE} -f Makefile clean jvmg ALT_BOOTDIR=/usr/lib/jvm/jdk1.7.0_80 ARCH_DATA_MODEL=64 LANG=C
复制代码

一直下一步,而后等待build成功。成功后在项目上右键点击属性,这里修改三个参数。
运行命令修改:

/home/java/openjdk/hotspot/build/linux/linux_amd64_compiler2/jvmg/gamma -XX:StopInterpreterAt=1 -version /home/java/openjdk/hotspot/build/linux/linux_amd64_compiler2/jvmg/Queens
复制代码

运行目录定位到/home/java/openjdk/hotspot/build/linux/linux_amd64_compiler2/jvmg
环境修改成jvmg目录下的env.sh中的参数 CLASS_PATH JAVA_HOME LD_LIBRART_PATH

最后就能够进行运行调试了,启动的main入口见图。

相关文章
相关标签/搜索