最近利用闲暇时间看了看《深刻理解java虚拟机》来提升自身得知识储备,再这里准备将读书学习到得知识和我的的心得记录下来。首先调整好本身的心态,不要浮躁,由于编译阶段会无限踩坑。html
这本书得里用得是Ubuntu系统,在这里我为了少踩坑放弃了以前一直使用得Centos7改成使用Ubuntu。VMware和Ubuntu系统安装比较简单,这里我也是参照一篇博客安装得,按照步骤安装就能够了,这里我用的乌班图版本为ubuntu-14.04.6-desktop-amd64,这里没有使用跟本书写着用的Ubuntu-10版本的,由于10版本的更新源实在太难找了。
VMware上安装乌班图系统参照此篇博客
固然,这里面仍是略微有些坑。java
首先打开终端,输入指令: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
若是安装了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
复制代码
$ 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
复制代码
$ 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
复制代码
再解压好的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
复制代码
好了,轻松愉快的阅读和复制粘贴工做结束,下面就是最开心的踩坑阶段,调整好本身的心情,打开百度和Google,准备开始一场烧脑的网络冲浪吧。网络
* 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
复制代码
/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
复制代码
上面的路径须要根据本身的状况进行修改。
/home/pgc/Downloads/openjdk/hotspot/src/share/vm/runtime/interfaceSupport.hpp:430:0: error: “__LEAF” redefined [-Werror]
#define __LEAF(result_type, header) \
^

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
复制代码
修改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
复制代码
上面的行数有可能有略微误差,找到行数的附近而后根据关键字查找就能够。
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
以上的问题应该还不是编译openjdk全部的坑,可能有些问题我尚未遇到,但这些坑就已经让我搞了三天的时间才搞定,若是遇到其余比较奇葩的坑,那只能自行baidu和Google了,最终顺利的话静静等待10分钟左右(依每人各电脑性能不一样,时间可能不同)的漫长等待,最终就编译好了,编译完成后会打印一下信息。
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
,正确会输出一下日志。
若是有人按照个人步骤作很是完美的成功了,那么恭喜你。
在上一步./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
,果真就成功了。
搞完上面两步,距离成功只剩一点点了,最后来下载安装netBeans,直接官网下载就能够,我安装的是8.0版本的,要选择支持C/C++开发的那个版本。 安装成功后打开netBeans,新建项目。选择基于现有源代码的C/C++项目。
/home/java/openjdk/hotspot
,选择定制,下一步。
${MAKE} -f Makefile clean jvmg ALT_BOOTDIR=/usr/lib/jvm/jdk1.7.0_80 ARCH_DATA_MODEL=64 LANG=C
复制代码
/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