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

jopen 9年前發布 | 21K 次閱讀 JVM Java開發

簡介&歷史

正如有些人已經知道的那樣,從Java7開始,OpenJDK就是Java的參考實現(Reference Implementation)。下圖的時間線可以讓你了解一下OpenJDK的歷史。

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

OpenJDK歷史(2006至今)

看看OpenJDK更詳細的過去現在和將來[1]

如果你想了解從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/JVM是如何構建的?看看OpenJDK吧!

代碼的組成以及語言的分解構成(比例是估計的)

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中摘錄出的一個代碼片段——http://hg.openjdk.java.net/jdk6/jdk6/hotspot/raw-file/a541ca8fa0e3/src/share/vm/memory/universe.cpp [10]:

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及其隸屬項目由以下組織支持發展:JCPOpenjdk team),JUGs如London Java CommunitySouJava和巴西其他的JUGs,歐洲許多的JUGs比如BGJUG (Bulgarian JUG) [18], BeJUG (Belgium JUG)[19],Macedonian JUG [20],還有許多其他的比較小的JUGs。我們希望未來會有更多JUGs組織和個人參與進來。如果你或你的JUG希望參與請聯系我們。

原文鏈接: javacodegeeks 翻譯: ImportNew.com - 范 忠瑞
譯文鏈接: http://www.importnew.com/14610.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!