专栏名称: ImportNew
伯乐在线旗下账号,专注Java技术分享,包括Java基础技术、进阶技能、架构设计和Java技术领域动态等。
目录
相关文章推荐
沉默王二  ·  后端行情变了,差别真的挺大! ·  昨天  
沉默王二  ·  后端行情变了,差别真的挺大! ·  昨天  
芋道源码  ·  效率爆表:30款 IDEA ... ·  3 天前  
芋道源码  ·  一款开源的通用PDF处理神器,功能强悍! ·  4 天前  
Java编程精选  ·  注解+反射优雅的实现Excel导入导出(通用 ... ·  1 周前  
芋道源码  ·  架构设计原则:选择 SPI 还是 API ? ·  1 周前  
51好读  ›  专栏  ›  ImportNew

Java / JVM 是如何构建的?看看 OpenJDK 吧

ImportNew  · 公众号  · Java  · 2017-06-08 13:01

正文

(点击上方蓝字,快速关注我们)


编译:ImportNew - fzr

如有好文章投稿,请点击 → 这里了解详情


简介&历史


正如有些人已经知道的那样,从Java7开始,OpenJDK就是Java的参考实现(Reference Implementation)。下图的时间线可以让你了解一下OpenJDK的历史。


OpenJDK历史(2006至今)


看看OpenJDK更详细的过去现在和将来[1]


https://www.slideshare.net/neomatrix369/adopt-openjdk-the-past-the-present-the-future


如果你想了解从Oracle,Red Hat,etcetera等供应商那里下载得来的JDK或JRE库,那么可以告诉你,它们都是起源于OpenJDK。每个供应商在此基础上添加额外的部件。出于安全,专利或其他的考虑,这些额外的添加部分并不公开源码。


OpenJDK由什么组成?


OpenJDK由许多软件库组成,主要有corba,hotspot,jaxp,jaxws,jdk,langtools,以及nashorn。在OpenJDK8和OpenJDK9之间没有新的软件库加入,但有很多改变和结构调整,主要是因为Jigsaw——Java自身的模块化[2][3][4][5]。


代码的组成以及语言的分解构成(比例是估计的)


Java语言和平台是如何构建的?


Java通过引导一个旧版本的Java——例如,Java以其自身为构件建立。旧的组件被组合在一起创建一个新的组件,即成为下一阶段的结构单元。关于这种自展的一个很好的例子请参考 Scheme from Scratch或是 Wikipedia [7]。


OpenJDK8使用JDK7编译和构建,类似地,OpenJDK9 则使用JDK8编译构建。理论上,OpenJDK8是可以使用从其自身创建的影像编译的,同理,OpenJDK9也能用OpenJDK9编译。使用一个叫做循环启动影像的进程——创建OpenJDK的JDK影像,使用同样的影像,OpenJDK再一次被编译。也可以用make命令实现OpenJDK的编译:


$ make bootcycle-images # Build images twice, second time with newly built JDK


make命令在OpenJDK8和OpenJDK9下都提供了很多设置选项,可以通过命名的方式建立独立的组件或模块。如下:


$ make [component-name] | [module-name]


甚至并行运行多个构建过程,如下:


$ make JOBS= # Run parallel make jobs


最后,用install选项安装上述已构建的组件,如下:


$ make install


一些被神话了的东西


具体来说,OpenJDK或是Hotspot都不完全是用C或C++写的,代码库中相当一部分代码是良好的OLE(对象连接与嵌入)Java(详细请看上文的组成图表)。所以对OpenJDK作出贡献并不要求你必须是核心硬件开发者。即使是底层的C/C++代码库也不是那么让人望而生畏。下面就是从HotSpot repo的vm/memory/universe.cpp中摘录出的一个代码片段。


Universe::initialize_heap()

 

if (UseParallelGC) {

#ifndef SERIALGC

Universe::_collectedHeap = new ParallelScavengeHeap();

#else // SERIALGC

fatal("UseParallelGC not supported in this VM.");

#endif // SERIALGC

 

} else if (UseG1GC) {

#ifndef SERIALGC

G1CollectorPolicy* g1p = new G1CollectorPolicy();

G1CollectedHeap* g1h = new G1CollectedHeap(g1p);

Universe::_collectedHeap = g1h;

#else // SERIALGC

fatal("UseG1GC not supported in java kernel vm.");

#endif // SERIALGC

 

} else {

GenCollectorPolicy* gc_policy;

 

if (UseSerialGC) {

gc_policy = new MarkSweepPolicy();

} else if (UseConcMarkSweepGC) {

#ifndef SERIALGC

if (UseAdaptiveSizePolicy) {

gc_policy = new ASConcurrentMarkSweepPolicy();

} else {

gc_policy = new ConcurrentMarkSweepPolicy();

}

#else // SERIALGC

fatal("UseConcMarkSweepGC not supported in this VM.");

#endif // SERIALGC

} else { // default old generation

gc_policy = new MarkSweepPolicy();

}

 

Universe::_collectedHeap = new GenCollectedHeap(gc_policy);

(请注意上述代码片段可能已在发布在本文后的时间里有所变更了)


从上面的代码块中可以明显看出的是,我们的目的在于展示如何使用预编译符号创建HotSpot代码来支持某种类型的GC(GenCollector),比如Serial GC(串行GC)或者Parallel GC(并行GC)。在上述代码块中,在一种或多种GC转换器被触发之前就已经选择确定了GC策略的类型了,比如,当UseAdaptiveSizePolicy被激活后,才可以选择Asynchronous Concurrent Mark and Sweep策略。在Use Serial GC和Use Concurrent Mark Sweep GC二者仅选其一的情况下,被选中的GC策略就是Mark and Sweep策略。除了提供读起来像英文一样流畅的格式简洁的代码之外,又说了这么多,已经相当清楚了,再多说就很啰嗦了。


更多注释可以在Adopt OpenJDK Intermediate & Advance experiences [11] 文件夹的Deep Dive Hotspot stuff部分找到。


构建自己的JDK或JRE的步骤


早些时候我们提到JDK和JRE的影像——这些不再是只给Java世界中的大玩家们提供了,你和我都能很轻易的构建这样的影像。这过程中的步骤已经被简化了,想快速开始请参看 Adopt OpenJDK Getting Started Kit 和 Adopt OpenJDK Intermediate & Advance experiences 文件。想要看更详细的版本请参看 Adopt OpenJDK home page。要从OpenJDK代码库中基本构建一个JDK影像,总结起来就是下面的几个命令:


(启动过程被简化了,忽略了一些命令,访问上述链接可以得到准确的操作步骤)


$ hg clone http://hg.openjdk.java.net/jdk8/jdk8 jdk8 (a)...OpenJDK8


或者


$ hg clone http://hg.openjdk.java.net/jdk9/jdk9 jdk9 (a)...OpenJDK9

$ ./get_sources.sh (b)

$ bash configure (c)

$ make clean images (d)


(设置的步骤和一些命令省略了,查看上面的链接可以查看更详细的步骤)


解释一下上述每个步骤的工作:


就像使用克隆版本库一样复制OpenJDK每次修改的版本。


一旦(a)已经完成,进入新创建的文件夹,执行get_sources.sh命令,等价于一次git fetch命令(抓取)或一次git pull命令(拉取远程仓库)。因为步骤(a)中只是降低基础文件而不是所有文件的成本。


这里运行一个脚本检查并创建编译与构建过程所需的配置


步骤(c)完成后,我们就算是从构建好的模块中完成了一个JDK和JRE影像文件的编译,构建和创建。


正如你看到的这样,这些步骤易如反掌,照做就可以建立一个自定义工具或者JDK/JRE影像[步骤a只需要执行一次]。


好处


• 促进Java语言&平台的发展和改进

• 了解Java语言和平台的内部构件

• 在达到以上两点的同时了解OS平台和其他技术

• 参与到F/OSS项目中

• 保持立于Java/JVM范畴的最新动态之上

• 提供有助于专业且还不能从其他如书籍,训练,工作实习,大学课程等来源获得的知识和经验

• 事业提升

• 个人发展(软技能及网络)


贡献


加入项目Adopt OpenJDK和 Betterrev,向我们提供这些项目中任何与java有关的反馈。可以从加入Adoption Discuss邮件列表和其他OpenJDK相关的邮件列表开始,这些可以让你了解OpenJDK相关的最新进展和变化。为你看到的任何项目建立分支库(通过github中的fork repo),然后提交自己的改变(通过github中发起一个Pull Request)。


感谢与支持


Adopt OpenJDK及其隶属项目由以下组织支持发展:JCP(Openjdk team),JUGs如London Java Community,SouJava和巴西其他的JUGs,欧洲许多的JUGs比如BGJUG (Bulgarian JUG) [18], BeJUG (Belgium JUG)[19],Macedonian JUG [20],还有许多其他的比较小的JUGs。我们希望未来会有更多JUGs组织和个人参与进来。如果你或你的JUG希望参与请联系我们。


看完本文有收获?请转发分享给更多人

关注「ImportNew」,提升Java技能