1. 程式人生 > >虛擬機器--第一章走進java--(抄書)

虛擬機器--第一章走進java--(抄書)

這是本人閱讀周志明老師的《深入理解Java虛擬機器》第二版抄寫的,有很多省略,不適合直接閱讀,需要閱讀請出門左轉淘寶,右轉京東,支援周老師(侵權請聯絡刪除)

第一章走近java

世界上並沒有完美的程式,但我們並不因此而沮喪,因為寫程式本來就是一個不斷追求完美的過程。

1.1概述

java不僅僅是一門程式語言,還是一個由一系列計算機軟體和規範形成的技術體系,這個技術體系提供了完整的用於軟體開發和跨平臺部署的支援環境,並廣泛應用於嵌入式系統、移動終端、企業伺服器、大型機等各種場合。時至今日,java技術體系已經吸引了900多萬軟體開發者,這是全球最大的軟體開發團隊。使用java技術體系的裝置多達幾十億臺,其中包括11億多臺個人計算機‘30億部行動電話及其他手持裝置、數量眾多的只能卡、以及大量機頂盒、導航系統和其他裝置。

java能獲得如此廣泛的認可,除了它有一門結構嚴謹、面向物件的程式語言之外,還有許多不可忽視的優點:它擺脫了硬體平臺的束縛,實現了“一次編寫,到處執行”的理想;它提供了一個相對安全的記憶體管理和訪問機制,避免了絕大部分的記憶體洩漏和指標越界問題;它實現了熱點程式碼檢測和執行時編譯及優化,這使得java應用能隨著執行時間的增加而獲得更高的效能;它有一套完善的應用程式介面,還有無數來自商業機構和開源社群的第三方類庫來幫助它實現各種各樣的功能……java所帶來的這些好處使程式的開發效率得到了很大的提升。作為一名java程式設計師,在編寫程式時除了盡情發貨java的各種優勢外,還應該去了解和思考一下java技術體系中這些技術特性是如何實現的。認識這些技術運作的本質,是自己思考“程式這樣寫好不好”的基礎和前提。當我們在使用一種技術時,如果不再依賴書本和他人就能得到這些問題的答案,那才算上升到了“不惑”的境界。

1.2java技術體系

從廣義上講,Clojure、JRuby、Groovy等執行與java虛擬機器上的語言及其相關的程式都屬於java技術體系中的一員。如果僅從傳統意義上來看,Sun官方所定義的java技術體系包括以下幾個組成部分:

  • java程式設計語言
  • 各種硬體平臺上的java虛擬機器
  • Class檔案格式
  • Java API類庫
  • 來自商業機構和開源社群的第三方java類庫
    我們可以把java程式設計語言、java虛擬機器、javaAPI類庫這三部分統稱為JDK,JDK是用於支援java程式開發的最小環境,在後面的內容中,為了講解方便,有一些地方會以JDK來代替整個java技術體系。另外,可以把java API類庫中的java SE API子集和java虛擬機器這兩部分統稱為JRE,JRE是支援java程式執行的標準環境。

按照java技術關注的重點業務領域來劃分,java技術體系可以劃分為4個平臺,可以分為:

  • java Card:支援一些java小程式(Applets)執行在小記憶體裝置(如智慧卡)上的平臺。
  • java Me:支援java程式執行在移動終端(手機,PDA)上的平臺,對java API有所精簡,並加入了針對移動終端的支援,這個版本以前稱為J2ME
  • java SE:支援面向桌面級應用(如Windows下的應用程式)的java平臺,提供了完整的java核心API,這個版本以前稱為J2SE。
  • java EE:支援使用多層架構的企業應用的java平臺,除了提供java SE API外,還對其做了大量的擴充並提供了相關的部署支援,這個版本以前稱為J2EE。

1.3java發展史

從第一個java版本誕生到現在已經有25年的時間了。滄海桑田一瞬間,轉眼25年過去了,我們看到JDK已經發展到了11版。在25年裡還誕生了無數和java相關的產品、技術和標準。現在讓我們走入時間隧道,從孕育java語言的時代開始,再來回顧一下java的發展軌跡和歷史變遷。
1991年4月,由James Gosling博士領導的綠色計劃開始啟動,此計劃的目的是開發一種能夠在各種消費性電子產品(如機頂盒、冰箱、收音機等)上執行的程式架構。這個計劃的產品就是java語言的前身:Oak(橡樹)。Oak當時在消費品市場上並不算成功,但隨著1995年網際網路潮流的興起,Oak迅速找到了最適合自己發展的市場定位並蛻變成為java語言。
1995年5月23日,Oak語言改名為java,並在SunWord打回上正式公佈java1.0版本。java語言第一次提出了“Write Once,Run Anywhere”的口號。
1996年1月23日,JDK1.0釋出,java語言有了第一個正式版本的執行環境。JDK1.0提供了一個純解釋執行的Java虛擬機器實現(Sun ClassIc VM)。JDK1.0版本的代表技術包括:java虛擬機器、Applet、AWT等。
1996年4月,10個最主要的作業系統供應商申明將在其產品中嵌入java技術。同年9月,已有大約8.3萬個網頁應用了java技術來製作。在1996年5月底,Sun公司在美國舊金山舉行了首屆JavaOne大會,從此JavaOne成為全世界數百萬java語言開發者每年一度的技術盛會。
1997年2月19日,Sun公司釋出了JDK1.1,java技術的一些最基礎的支撐點(如JDBC等)都是在JDK1.1版本中釋出的,JDK1.1版的技術代表有:JAR檔案格式、JDBC、JavaBean、RMI。java語法也有了一定的發展,如內部類和反射都是在這個時候出現的
1999年4月8日,JDK1.1一共釋出了1.1.0~1.1.8九個版本。從1.1.4之後,每個JDK版本都有一個自己的名字(工程代號)。。。。
1998年12月4日,JDK迎來了一個里程碑式的版本JDK1.2,工程代號為Playground(競技場),sun在這個版本中把java技術體系拆分為3個方向,分別是面向桌面的J2SE、面向企業級應用的J2EE和麵向手機等移動終端的J2ME。在這個版本中出現的代表性的技術非常多,如EJB、javaPlug-in、java IDL、Swing等,並且在這個版本中java虛擬機器第一次內建了JIT編譯器(JDK1.2中曾並存過3個虛擬機器,Classic VM、HotSpot VM、Exact VM),其中Exact VM只在Solaris平臺出現過;後面兩個虛擬機器都是內建JIT編譯器,而之前版本所帶的Classic VM只能以外掛的形式使用JIT編譯器)。在語言和API級別上,java添加了strict分片關鍵字與現在java編碼之中極為常用的一系列Collection集合類。在1999年3月和7月,分別有JDK1.2.1和JDK1.2.2兩個小版本釋出。
1999年4月27日,HotSpot虛擬機發布,HotSpot最初由一家名為“longview Technologies”的小公司開發,因為HotSpot的優異表現,這家公司在1997年被Sun公司收購了。HotSpot虛擬機發布時是作為JDK1.2的附加程式提供的,後來他成為了JDK1.3及之後所有版本的Sun JDK的預設虛擬機器。
2000年5月8日,工程代號為Kestrel(美洲紅隼)的JDK1.3釋出,JDK1.3相對於JDK1.2的改進主要表現在一些類庫上(如數學運算和新的Tiner API等),JNDI服務從JDK1.3開始被作為一項平臺級服務提供(之前只是一項擴充套件),使用CORBA IIOP來實現RMI的通訊協議等等,這個版本還對Java 2D做了很多改進,提供了大量新的Java 2D API,並且新添加了JavaSound類庫。JDK 1.3有1個修正版本JDK 1.3.1,工程代號為Ladybird(瓢蟲),於2001年5月17日釋出。
自從JDK 1.3開始,Sun維持了一個習慣:大約每隔兩年釋出一個JDK的主版本,以動物命名,期間釋出的各個修正版本則以昆蟲作為工程名稱
2002年2月13日,2002年2月13日,JDK 1.4釋出,工程代號為Merlin(灰背隼)。JDK 1.4是Java真正走向成熟的一個版本,Compaq、Fujitsu、SAS、Symbian、IBM等著名公司都有參與甚至實現自己獨立的JDK 1.4。哪怕是在十多年後的今天,仍然有許多主流應用(Spring、Hibernate、Struts等)能直接執行在JDK 1.4之上,或者繼續釋出能執行在JDK 1.4上的版本。JDK 1.4同樣釋出了很多新的技術特性,如正則表示式、異常鏈、NIO、日誌類、XML解析器和XSLT轉換器等。JDK 1.4有兩個後續修正版:2002年9月16日釋出的工程代號為Grasshopper(蚱蜢)的JDK 1.4.1與2003年6月26日釋出的工程代號為Mantis(螳螂)的JDK 1.4.2。
2002年前後還發生了一件與Java沒有直接關係,但事實上對Java的發展程序影響很大的事件,那就是微軟公司的.NET Framework釋出了。這個無論是技術實現上還是目標使用者上都與Java有很多相近之處的技術平臺給Java帶來了很多討論、比較和競爭,.NET平臺和Java平臺之間聲勢浩大的孰優孰劣的論戰到目前為止都在繼續。
2004年9月30日,JDK 1.5釋出,工程代號Tiger(老虎)。從JDK 1.2以來,Java在語法層面上的變換一直很小,而JDK 1.5在Java語法易用性上做出了非常大的改進。例如,自動裝箱、泛型、動態註解、列舉、可變長引數、遍歷迴圈(foreach迴圈)等語法特性都是在JDK 1.5中加入的。在虛擬機器和API層面上,這個版本改進了Java的記憶體模型(Java Memory Model,JMM)、提供了java.util.concurrent併發包等。另外,JDK 1.5是官方宣告可以支援Windows 9x平臺的最後一個JDK版本。
2006年12月11日,JDK 1.6釋出,工程代號Mustang(野馬)。在這個版本中,Sun終結了從JDK 1.2開始已經有8年曆史的J2EE、J2SE、J2ME的命名方式,啟用Java SE 6、Java EE 6、Java ME 6的命名方式。JDK 1.6的改進包括:提供動態語言支援(通過內建Mozilla JavaScript Rhino引擎實現)、提供編譯API和微型HTTP伺服器API等。同時,這個版本對Java虛擬機器內部做了大量改進,包括鎖與同步、垃圾收集、類載入等方面的演算法都有相當多的改動。
在2006年11月13日的JavaOne大會上,Sun公司宣佈最終會將Java開源,並在隨後的一年多時間內,陸續將JDK的各個部分在GPL v2(GNU General Public License v2)協議下公開了原始碼,並建立了OpenJDK組織對這些原始碼進行獨立管理。除了極少量的產權程式碼(Encumbered Code,這部分程式碼大多是Sun本身也無許可權進行開源處理的)外,OpenJDK幾乎包括了Sun JDK的全部程式碼,OpenJDK的質量主管曾經表示,在JDK 1.7中,Sun JDK和OpenJDK除了程式碼檔案頭的版權註釋之外,程式碼基本上完全一樣,所以OpenJDK 7與Sun JDK 1.7本質上就是同一套程式碼庫開發的產品。
JDK 1.6發布以後,由於程式碼複雜性的增加、JDK開源、開發JavaFX、經濟危機及Sun收購案等原因,Sun在JDK發展以外的事情上耗費了很多資源,JDK的更新沒有再維持兩年釋出一個主版本的發展速度。JDK 1.6到目前為止一共釋出了37個Update版本,最新的版本為Java SE 6 Update 37,於2012年10月16日釋出。
2009年2月19日,工程代號為Dolphin(海豚)的JDK 1.7完成了其第一個里程碑版本。根據JDK 1.7的功能規劃,一共設定了10個里程碑。最後一個里程碑版本原計劃於2010年9月9日結束,但由於各種原因,JDK 1.7最終無法按計劃完成。
從JDK 1.7最開始的功能規劃來看,它本應是一個包含許多重要改進的JDK版本,其中的Lambda專案(Lambda表示式、函數語言程式設計)(jdk8中得以實現)、**Jigsaw專案(虛擬機器模組化支援)(JDK9中得以實現) **、動態語言支援、GarbageFirst收集器和Coin專案(語言細節進化)等子專案對於Java業界都會產生深遠的影響。在JDK 1.7開發期間,Sun公司由於相繼在技術競爭和商業競爭中都陷入泥潭,公司的股票市值跌至僅有高峰時期的3%,已無力推動JDK 1.7的研發工作按正常計劃進行。為了儘快結束JDK 1.7長期“跳票”的問題,Oracle公司收購Sun公司後不久便宣佈將實行“B計劃”,大幅裁剪了JDK 1.7預定目標,以便保證JDK 1.7的正式版能夠於2011年7月28日準時釋出。“B計劃”把不能按時完成的Lambda專案、Jigsaw專案和Coin專案的部分改進延遲到JDK 1.8之中。最終,JDK 1.7的主要改進包括:提供新的G1收集器(G1在釋出時依然處於Experimental狀態,直至2012年4月的Update 4中才正式“轉正”)、加強對非Java語言的呼叫支援(JSR-292,這項特性到目前為止依然沒有完全實現定型)、升級類載入架構等。
到2012年為止,JDK 1.7已經發布了9個Update版本,最新的Java SE 7 Update 9於2012年10月16日釋出。從Java SE 7 Update 4起,Oracle開始支援Mac OS X作業系統,並在Update 6中達到完全支援的程度,同時,在Update 6中還對ARM指令集架構提供了支援。至此,官方提供的JDK可以運行於Windows(不含Windows 9x)、Linux、Solaris和Mac OS平臺上,支援ARM、x86、x64和Sparc指令集架構型別。
2009年4月20日,Oracle公司宣佈正式以74億美元的價格收購Sun公司,Java商標從此正式歸Oracle所有(Java語言本身並不屬於哪間公司所有,它由JCP組織進行管理,儘管JCP主要是由Sun公司或者說Oracle公司所領導的)。由於此前Oracle公司已經收購了另外一家大型的中介軟體企業BEA公司,在完成對Sun公司的收購之後,Oracle公司分別從BEA和Sun中取得了目前三大商業虛擬機器的其中兩個:JRockit和HotSpot,Oracle公司宣佈在未來1~2年的時間內,將把這兩個優秀的虛擬機器互相取長補短,最終合二為一。可以預見在不久的將來,Java虛擬機器技術將會產生相當巨大的變化。
2014年JDK8釋出
2017年JDK9釋出
2018年3月JDK10釋出
2018年9月JDK11釋出

java虛擬機發展史

從1996年初Sun公司釋出的JDK1.0中所包含的Sun Classic VM到今天,曾經湧現、泯滅過許多或經典或優秀或有特色的虛擬機器實現,在這一節中,我們先暫且把程式碼與技術放下,一起來回顧一下java虛擬機器家族的發展軌跡和歷史變遷。

1.4.1 Sun Classic/Exact Vm

以今天的視角來看,SunClassic VM的技術可能很原始,這款虛擬機器的使命也早以終結。但僅憑它“世界上第一款商用java虛擬機器”的頭銜,就足夠有讓歷史記住它的理由。
1996年1月23日,Sun公司釋出JDK1.0,java語言首次擁有了商用的正式執行環境,這個JDK中所帶的虛擬機器就是Classic VM。這款虛擬機器只能使用純直譯器方式來執行java程式碼,如果要使用JIT編譯器,就必須進行外掛。但如果外掛了JIT編譯器,JIT編譯器就完全接管了虛擬機器的執行系統,直譯器便不再工作了。使用者在這款虛擬機器上執行java-version命令,將會看到類似下面這行輸出:
java version “1.2.3”
Classic VM(build JDK-1.2.2-001,green threads,sunwjit)
其中的“Sunwjit”就是sun提供的外掛編譯器其他類似的外掛編譯器還有Symantec JIT和shuJIT等。由於直譯器和編譯器不能配合工作,這就意味著如果要使用編譯器執行,編譯器就不得不對每一個方法、每一行程式碼都進行編譯,而無論它們執行的頻率是否具有編譯的價值。基於程式響應時間的壓力,這些編譯器根本不敢應用編譯耗時稍高的優化技術,因此這個階段的虛擬機器即使用了JIT編譯器輸出原生代碼,執行效率也和傳統的C/C++程式有很大差距,“Java語言很慢”的形象就是在這時候開始在使用者心中樹立起來的。
Sun的虛擬機器團隊努力去解決Classic VM所面臨的各種問題,提升執行效率。在JDK 1.2時,曾在Solaris平臺上釋出過一款名為Exact VM的虛擬機器,它的執行系統已經具備現代高效能虛擬機器的雛形:如兩級即時編譯器、編譯器與直譯器混合工作模式等。Exact VM因它使用準確式記憶體管理(Exact Memory Management,也可以叫Non-Conservative/Accurate Memory Management)而得名,即虛擬機器可以知道記憶體中某個位置的資料具體是什麼型別。譬如記憶體中有一個32位的整數123456,它到底是一個reference型別指向123456的記憶體地址還是一個數值為123456的整數,虛擬機器將有能力分辨出來,這樣才能在GC(垃圾收集)的時候準確判斷堆上的資料是否還可能被使用。由於使用了準確式記憶體管理,Exact VM可以拋棄以前Classic VM基於handler的物件查詢方式(原因是進行GC後物件將可能會被移動位置,如果將地址為123456的物件移動到654321,在沒有明確資訊表明記憶體中哪些資料是reference的前提下,虛擬機器是不敢把記憶體中所有為123456的值改成654321的,所以要使用控制代碼來保持reference值的穩定),這樣每次定位物件都少了一次間接查詢的開銷,提升執行效能。
雖然Exact VM的技術相對Classic VM來說先進了許多,但是在商業應用上只存在了很短暫的時間就被更為優秀的HotSpot VM所取代,甚至還沒有來得及釋出Windows和Linux平臺下的商用版本。而Classic VM的生命週期則相對長了許多,它在JDK 1.2之前是Sun JDK中唯一的虛擬機器,在JDK 1.2時,它與HotSpot VM並存,但預設使用的是Classic VM(使用者可用java-hotspot引數切換至HotSpot VM),而在JDK 1.3時,HotSpot VM成為預設虛擬機器,但Classic VM仍作為虛擬機器的“備用選擇”釋出(使用java-classic引數切換),直到JDK 1.4的時候,Classic VM才完全退出商用虛擬機器的歷史舞臺,與Exact VM一起進入了Sun Labs Research VM之中。

1.4.2 Sun HotSpot Vm

提起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編譯器與混合的執行時系統

1.4.3 Sun Mobile-Embedded VM/Meta-Circular VM

Sun 公司所研發的虛擬機器可不僅有前面介紹的伺服器、桌面領域的商用虛擬機器,除此之外,Sun公司面向移動和嵌入式市場也釋出過虛擬機器產品,另外還有一類虛擬機器,在設計之初就,沒抱有商用的目的,僅僅是用於研究,驗證某些技術和觀點,又或者是作為一些規範的標準實現。這些虛擬機器對於大部分不從事相關領域開發的java程式設計師來說可能比較陌生。Sun公司釋出的其他java虛擬機器有
(1)KVM
KVM中的K是“Kilobyte”的意思,它強調簡單、輕量、高度可移植,但是執行速度比較慢。在Android、iOS等智慧手機作業系統出現前曾經在手機平臺上得到非常廣泛的應用。
(2)CDC/CLDC HotSpot Implementation
CDC/CLDC全稱是Connected(Limited)Device Configuration,在JSR-139/JSR-218規範中進行定義,它希望在手機、電子書、PDA等裝置上建立統一的Java程式設計介面,而CDC-HI VM和CLDC-HI VM則是它們的一組參考實現。CDC/CLDC是整個Java ME的重要支柱,但從目前Android和iOS二分天下的移動數字裝置市場看來,在這個領域中,Sun的虛擬機器所面臨的局面遠不如伺服器和桌面領域樂觀。
(3)Squawk VM
Squawk VM由Sun公司開發,運行於Sun SPOT(Sun Small Programmable Object Technology,一種手持的WiFi裝置),也曾經運用於Java Card。這是一個Java程式碼比重很高的嵌入式虛擬機器實現,其中諸如類載入器、位元組碼驗證器、垃圾收集器、直譯器、編譯器和執行緒排程都是Java語言本身完成的,僅僅靠C語言來編寫裝置I/O和必要的原生代碼。
(4)JavaInJava
JavaInJava是Sun公司於1997年~1998年間研發的一個實驗室性質的虛擬機器,從名字就可以看出,它試圖以Java語言來實現Java語言本身的執行環境,既所謂的“元迴圈”(Meta-Circular,是指使用語言自身來實現其執行環境)。它必須執行在另外一個宿主虛擬機器之上,內部沒有JIT編譯器,程式碼只能以解釋模式執行。在20世紀末主流Java虛擬機器都未能很好解決效能問題的時代,開發這種專案,其執行速度可想而知。
(5)Maxine VM
Maxine VM和上面的JavaInJava非常相似,它也是一個幾乎全部以Java程式碼實現(只有用於啟動JVM的載入器使用C語言編寫)的元迴圈Java虛擬機器。這個專案於2005年開始,到現在仍然在發展之中,比起JavaInJava,Maxine VM就顯得“靠譜”很多,它有先進的JIT編譯器和垃圾收集器(但沒有直譯器),可在宿主模式或獨立模式下執行,其執行效率已經接近了HotSpot Client VM的水平。

1.4.4 BEA JRockit/IBM J9 VM

前面介紹了Sun公司的各種虛擬機器,除了Sun公司以外,其他組織、公司也研發過不少虛擬機器實現,其中規模最大、最著名的就是BEA和IBM公司了。
JRockit VM曾經號稱“世界上速度最快的Java虛擬機器”(廣告詞,貌似J9 VM也這樣說過),它是BEA公司在2002年從Appeal Virtual Machines公司收購的虛擬機器。BEA公司將其發展為一款專門為伺服器硬體和伺服器端應用場景高度優化的虛擬機器,由於專注於伺服器端應用,它可以不太關注程式啟動速度,因此JRockit內部不包含解析器實現,全部程式碼都靠即時編譯器編譯後執行。除此之外,JRockit的垃圾收集器和MissionControl服務套件等部分的實現,在眾多Java虛擬機器中也一直處於領先水平。
IBM J9 VM並不是IBM公司唯一的Java虛擬機器,不過是目前其主力發展的Java虛擬機器。IBM J9 VM原本是內部開發代號,正式名稱是“IBM Technology for Java Virtual Machine”,簡稱IT4J,只是這個名字太拗口了一點,普及程度不如J9。J9 VM最初是由IBM Ottawa實驗室一個名為SmallTalk的虛擬機器擴充套件而來的,當時這個虛擬機器有一個bug是由8k值定義錯誤引起的,工程師花了很長時間終於發現並解決了這個錯誤,此後這個版本的虛擬機器就稱為K8了,後來擴展出支援Java的虛擬機器就被稱為J9了。與BEA JRockit專注於伺服器端應用不同,IBM J9的市場定位與Sun HotSpot比較接近,它是一款設計上從伺服器端到桌面應用再到嵌入式都全面考慮的多用途虛擬機器,J9的開發目的是作為IBM公司各種Java產品的執行平臺,它的主要市場是和IBM產品(如IBM WebSphere等)搭配以及在IBM AIX和z/OS這些平臺上部署Java應用。

1.4.5Azul VM/BEA Liquid VM

我們平時所提及的“高效能Java虛擬機器”一般是指HotSpot、JRockit、J9這類在通用平臺上執行的商用虛擬機器,但其實Azul VM和BEA Liquid VM這類特定硬體平臺專有的虛擬機器才是“高效能”的武器。
Azul VM是Azul Systems公司在HotSpot基礎上進行大量改進,運行於Azul Systems公司的專有硬體Vega系統上的Java虛擬機器,每個Azul VM例項都可以管理至少數十個CPU和數百GB記憶體的硬體資源,並提供在巨大記憶體範圍內實現可控的GC時間的垃圾收集器、為專有硬體優化的執行緒排程等優秀特性。在2010年,Azul Systems公司開始從硬體轉向軟體,釋出了自己的Zing JVM,可以在通用x86平臺上提供接近於Vega系統的特性。
Liquid VM即是現在的JRockit VE(Virtual Edition),它是BEA公司開發的,可以直接執行在自家Hypervisor系統上的JRockit VM的虛擬化版本,Liquid VM不需要作業系統的支援,或者說它自己本身實現了一個專用作業系統的必要功能,如檔案系統、網路支援等。由虛擬機器越過通用作業系統直接控制硬體可以獲得很多好處,如線上程排程時,不需要再進行核心態/使用者態的切換等,這樣可以最大限度地發揮硬體的能力,提升Java程式的執行效能。

Apache Harmony/Google Android Dalvik VM

這節介紹的Harmony VM和Dalvik VM只能稱做“虛擬機器”,而不能稱做“Java虛擬機器”,但是這兩款虛擬機器(以及所代表的技術體系)對最近幾年的Java世界產生了非常大的影響和挑戰,甚至有些悲觀的評論家認為成熟的Java生態系統有崩潰的可能。
Apache Harmony是一個Apache軟體基金會旗下以Apache License協議開源的實際兼容於JDK 1.5和JDK 1.6的Java程式執行平臺,這個介紹相當拗口。它包含自己的虛擬機器和Java庫,使用者可以在上面執行Eclipse、Tomcat、Maven等常見的Java程式,但是它沒有通過TCK認證,所以我們不得不用那麼一長串拗口的語言來介紹它,而不能用一句“Apache的JDK”來說明。如果一個公司要宣佈自己的執行平臺“兼容於Java語言”,那就必須要通過TCK(Technology Compatibility Kit)的相容性測試。Apache基金會曾要求Sun公司提供TCK的使用授權,但是一直遭到拒絕,直到Oracle公司收購了Sun公司之後,雙方關係越鬧越僵,最終導致Apache憤然退出JCP(Java Community Process)組織,這是目前為止Java社群最嚴重的一次“分裂”。
在Sun將JDK開源形成OpenJDK之後,Apache Harmony開源的優勢被極大地削弱,甚至連Harmony專案的最大參與者IBM公司也宣佈辭去Harmony專案管理主席的職位,並參與OpenJDK專案的開發。雖然Harmony沒有經過真正大規模的商業運用,但是它的許多程式碼(基本上是Java庫部分的程式碼)被吸納進IBM的JDK 7實現及Google Android SDK之中,尤其是對Android的發展起到了很大的推動作用。
說到Android,這個時下最熱門的移動數碼裝置平臺在最近幾年間的發展過程中所取得的成果已經遠遠超越了Java ME在過去十多年所獲得的成果,Android讓Java語言真正走進了移動數碼裝置領域,只是走的並非Sun公司原本想象的那一條路。
Dalvik VM是Android平臺的核心組成部分之一,它的名字來源於冰島一個名為Dalvik的小漁村。Dalvik VM並不是一個Java虛擬機器,它沒有遵循Java虛擬機器規範,不能直接執行Java的Class檔案,使用的是暫存器架構而不是JVM中常見的棧架構。但是它與Java又有著千絲萬縷的聯絡,它執行的dex(Dalvik Executable)檔案可以通過Class檔案轉化而來,使用Java語法編寫應用程式,可以直接使用大部分的Java API等。目前Dalvik VM隨著Android一起處於迅猛發展階段,在Android 2.2中已提供即時編譯器實現,在執行效能上有了很大的提高

Microsoft JVM及其他

在十幾年的Java虛擬機發展過程中,除去上面介紹的那些被大規模商業應用過的Java虛擬機器外,還有許多虛擬機器是不為人知的或者曾經“絢麗”過但最終湮滅的。我們以其中微軟公司的JVM為例來介紹一下。
也許Java程式設計師聽起來可能會覺得驚訝,微軟公司曾經是Java技術的鐵桿支持者(也必須承認,與Sun公司爭奪Java的控制權,令Java從跨平臺技術變為繫結在Windows上的技術是微軟公司的主要目的)。在Java語言誕生的初期(1996年~1998年,以JDK 1.2釋出為分界),它的主要應用之一是在瀏覽器中執行Java Applets程式,微軟公司為了在IE3中支援Java Applets應用而開發了自己的Java虛擬機器,雖然這款虛擬機器只有Windows平臺的版本,卻是當時Windows下效能最好的Java虛擬機器,它在1997年和1998年連續兩年獲得了《PC Magazine》雜誌的“編輯選擇獎”。但好景不長,在1997年10月,Sun公司正式以侵犯商標、不正當競爭等罪名控告微軟公司,在隨後對微軟公司的壟斷調查之中,這款虛擬機器也曾作為證據之一被呈送法庭。這場官司的結果是微軟公司賠償2000萬美金給Sun公司(最終微軟公司因壟斷賠償給Sun公司的總金額高達10億美元),承諾終止其Java虛擬機器的發展,並逐步在產品中移除Java虛擬機器相關功能。具有諷刺意味的是,到最後在Windows XP SP3中Java虛擬機器被完全抹去的時候,Sun公司卻又到處登報希望微軟公司不要這樣做。Windows XP高階產品經理Jim Cullinan稱:“我們花費了3年的時間和Sun打官司,當時他們試圖阻止我們在Windows中支援Java,現在我們這樣做了,可他們又在抱怨,這太具有諷刺意味了。”
我們試想一下,如果當年Sun公司沒有起訴微軟公司,微軟公司繼續保持著對Java技術的熱情,那Java的世界會變得怎麼樣呢?.NET技術是否會發展起來?但歷史是沒有假設的。其他在本節中沒有介紹到的Java虛擬機器還有(當然,應該還有很多筆者所不知道的):
JamVM.
cacaovm.
SableVM.
Kaffe.
Jelatine JVM.
NanoVM.
MRP.
Moxie JVM.
Jikes RVM.

展望java技術的未來

在2005年,java語言誕生10週年的SunOne技術大會上,java語言之父JamesGosling做了一場題為為“java技術下一個十年”的演講。。。。。

1.5.1模組化

模組化是解決解決應用系統與技術平臺越來越複雜、越來越龐大問題的一個重要途徑。無論是開發人員還是產品終端使用者,都不希望為了系統中的一小塊的功能而不得不下載、安裝、部署、及維護整套龐大的系統、站在整個軟體工業化的高度來看,模組化是建立各種功能的標準件的前提。最近幾年OSGi技術的迅速發展各個廠商在JCP中對模組化規範的激烈鬥爭,都能充分說明模組化技術的迫切和重要。
在未來的java平臺中,很可能會對模組化提出語法層面的支援(java9模組化已出

1.5.2混合語言

當單一的java開發已經無法滿足當前軟體的複雜需求時,越來越多基於java虛擬機器的語言開發被應用到軟體專案中,java平臺上的多語言混合程式設計正成為主流,每種語言都可以針對自己擅長的方面更好地解決問題。試想一下,在一個專案中,並行處理用Clojure語言編寫,展示層使用JRuby/Rails,中間層使用java,每個應用層都將使用不同的程式語言來完成,而且,介面對每一層的開發者都是透明的,各種語言之間的互動不存在任何困難,就像使用自己語言的原生APi一樣方便,因為它們最終執行在java虛擬機器之上。
在最近的幾年裡,Clojure、JRuby、Groovy等新生語言的使用人數不斷增長,而執行在java虛擬機器之上的語言數量也在迅速膨脹。
除了催生出大量的新語言外,許多已經有了很長曆史的程式語言也出現了基於java虛擬機器實現的版本,這樣使得混合程式設計對許多以前使用其他語言的“老”程式設計師也具備相當大的吸引力,軟體企業投入了大量資本的現有程式碼資產也能很好地保護起來。
對這些運行於java虛擬機器之上,java之外的語言,來自系統級、底層的支援正在迅速增強,以JSR-292為核心的一系列專案和功能改進,推動java虛擬機器從“java語言的虛擬機器”向“多語言虛擬機器”的方向發展

1.5.3多核並行

如今,CPU硬體的發展方向已經從高頻率轉變為多核心,隨著多核時代的來臨,軟體開發越來越關注並行程式設計的領域。早在JDK1.5就已經引入java.util.concurrent包實現了一個粗粒度的併發框架。而JDK1.7中加入的java.util.concurrent.forkjoin包則是對這個框架的一次重要擴充。Fork/Join模式是處理併發程式設計的一個經典方法。雖然不能解決所有的問題,但是在此模式的適用範圍之內,能夠輕鬆地利用多個CPU核心提供的計算資源來協作完成一個複雜的計算任務。通過Fork/Join模式,我們能夠更加順暢地過渡到多核時代
在java8中,將會提供lambda支援,這將會極大改善目前java語言不適合函數語言程式設計的現狀,函數語言程式設計的一個重要優點就是這樣的程式天然地適合並行執行,這對java語言在多核時代繼續保持主流語言的地位有很大幫助。
另外,在平行計算中必須提及的還有OpenJDK的子專案Sumatra,目前顯示卡的算術運算能力並行能力已經遠遠超過了CPU,在圖形運算領域以外發掘顯示卡的潛力是最近幾年計算機發展的方向之一,例如C語言的CUDA。Sumatra專案就是為java提供使用GPU和APU運算能力的工具,以後它將會直接提供java語言 層面的API,或者為lambda和其他JVM語言提供底層的並行運算支援。
在JDK外圍,也出現了專為滿足並行運算需求的計算框架,如Apache的Hadoop Map/Readuce,這是一個簡單易懂的並行框架,能夠執行在由上千個商用機器組成的大型叢集上,並且能以一種可靠的容錯方式並行處理TB級別的資料集。另外,還出現了諸如Scala、Clojure、及Erlang等天生就具備平行計算能力的語言。

1.5.4進一步豐富語法

java 5 曾經對java語法進行了一次擴充,這次擴充加入了自動裝箱、泛型、動態註解、列舉、可變長引數、迴圈遍歷等語法,使得java語言的精確性和易用性有了很大的進步。在java7中,對java語法進行了另一次大規模的擴充。Sun專門為改進java語法在OpenJDK中建立了Coin子專案來統一處理對java語法的細節修改,如二進位制的原生支援、在switch語句中支援字串、"<>"操作符、異常處理的改進、簡化變長引數方法呼叫、面向資源的try-catch-finally語句等都是在Coin專案中提交的內容。
處理Coin專案之外在JSR-335中定義的lambda表示式也將對java的語法和語言習慣產生很大的影響,面向很熟方式的程式設計可能會成為主流。

1.5.5 64位虛擬機器

在幾年之前,主流的CPU就開始支援64位架構了。java虛擬機器也在很早之前推出了支援64位系統的版本。但java程式執行在64位虛擬機器上需要付出的比較大的額外代價:首先是記憶體問題,由於指標膨脹和各種資料型別對其補白的原因,運行於64位系統上的java應用需要消耗更多的記憶體,通常要比32位系統額外增加10%~30%的記憶體消耗;其次,多個幾個的測試結果顯示,64位虛擬機器的執行速度在各項測試中幾乎全面落後於32位虛擬機器,兩者大約有15%左右的效能差距。
但在javaEE方面,企業級應用經常需要使用超過4GB的記憶體,對於64位虛擬機器的需求時非常迫切的,但由於上述原因,許多企業應用仍然選擇使用虛擬叢集等方式繼續在32位虛擬機器中進行部署。Sun也注意到了這些問題,並做出了一些改善,在JDK 1.6 Update 14之後,提供了普通物件指標壓縮功能(-XX:+UseCompressedOops,這個引數不建議顯式設定,建議維持預設由虛擬機器的Ergonomics機制自動開啟),在執行程式碼時,動態植入壓縮指令以節省記憶體消耗,但是開啟壓縮指標會增加執行程式碼數量,因為所有在Java堆裡的、指向Java堆內物件的指標都會被壓縮,這些指標的訪問就需要更多的程式碼才可以實現,而且並不只是讀寫欄位才受影響,在例項方法呼叫、子型別檢查等操作中也受影響,因為物件例項指向物件型別的引用也被壓縮了。隨著硬體的進一步發展,計算機終究會完全過渡到64位的時代,這是一件毫無疑問的事情,主流的虛擬機器應用也終究會從32位發展至64位,而虛擬機器對64位的支援也將會進一步完善。

1.6實戰:自己編譯JDK

想要一探JDK內部的實現機制,最便捷的路徑之一就是自己編譯一套JDK通過閱讀和跟蹤除錯JDK原始碼去了解java技術體系的原理,雖然門檻會高一點,但肯定會比閱讀各種書籍、文章更加貼近本質。另外,JDK中的許多底層方法都是本地化的,需要跟蹤這些方法的運作對JDK進行Hack的時候,都需要自己編譯一套JDK。
現在網路上有不少開源的JDK實現可以供我們選擇,如Apache Harmony、Open-JDK等。考慮到Sun系列的JDK是現在使用得最廣泛的JDK版本,筆者選擇了Open-JDK進行這次編譯實戰。

獲取JDK原始碼

首先要明確OpenJDK和Sun/OracleJDK之間,以及OpenJDK 6、Open JDK 7、Open JDK 7u、Open JDK 8等專案之間是什麼關係,這有助於確定接下來編譯要使用的JDK版本和原始碼分支。
從前面介紹的java發展史中我們瞭解到OpenJDK是Sun在2006年末把java開源而形成的專案,這裡的“開源”是通常意義上的原始碼開發形式,即原始碼是可被複用的例如IcedTea、UltraViolet都是從OpenJDK原始碼衍生出的發行版。但如果僅從“開源”字面意義(開放可閱讀的原始碼)上看,其實Sun自JDK 1.5之後就開始以Java Research License(JRL)的形式公佈過Java原始碼,主要用於研究人員閱讀(JRL許可證的開放原始碼至JDK 1.6 Update 23為止)。把這些JRL許可證形式的Sun/OracleJDK原始碼和對應版本的OpenJDK原始碼進行比較,發現除了檔案頭的版權註釋之外,其餘程式碼基本上都是相同的,只有字型渲染部分存在一點差異,Oracle JDK採用了商業實現,而OpenJDK使用的是開源的FreeType。當然,“相同”是建立在兩者共有的元件基礎上的,Oracle JDK中還會存在一些Open JDK沒有的、商用閉源的功能,例如從JRockit移植改造而來的Java Flight Recorder。預計以後JRockit的MissionControl移植到HotSpot之後,也會以Oracle JDK專有、閉源的形式提供。
再來看一下OpenJDK 6、OpenJDK 7、OpenJDK 7u和OpenJDK 8這幾個專案之間的關係,從圖1-7(依然是從Joe Darcy的OSCON 2011演示稿中擷取的圖片)來看,OpenJDK 7是始於JDK 6時期,當時JDK 6和JDK 6 Update 1已經發布,JDK 7已經開始研發了,所以OpenJDK 7是直接基於正在研發的JDK 7原始碼建立的。但考慮到OpenJDK 7的狀況在當時還不適合實際生產部署,因此在OpenJDK 7 Build 20的基礎上建立了OpenJDK 6分支,剝離掉JDK 7新功能的程式碼,形成一個可以通過TCK 6測試的獨立分支。
2012年7月,JDK 7正式釋出,在OpenJDK中也同步建立了OpenJDK 7 Update專案對JDK 7進行更新升級,以及OpenJDK 8專案開始下一個JDK大版本的研發。按照開發習慣,新的功能或Bug修復通常是在最新分支上進行的,當功能或修復在最新分支上穩定之後會同步到其他老版本的維護分支上。
OpenJDK 6、OpenJDK 7、OpenJDK 7u和OpenJDK 8的原始碼都可以在它們相應的網頁上找到,在本次編譯實踐中,筆者選用的專案是OpenJDK 7u,版本為7u6。
獲取OpenJDK原始碼有兩種方式,其中一種是通過Mercurial程式碼版本管理工具從Repository中直接取得原始碼(Repository地址:http://hg.openjdk.java.net/jdk7u/jdk7u),獲取過程如以下程式碼所示。
這是最直接的方式,從版本管理中看變更軌跡比看Release Note效果更好。但不足之處是速度太慢,雖然程式碼總容量只有300 MB左右,但是檔案數量太多,在筆者的網路下全部複製到本地需要數小時。另外,考慮到Mercurial不如Git、SVN、ClearCase或CVS之類的版本控制工具那樣普及,對於一般讀者,建議採用第二種方式,即直接下載官方打包好的原始碼包,讀者可以從Source Bundle Releases頁面(地址:http://jdk7.java.net/source.html)取得打包好的原始碼,到本地直接解壓即可。一般來說,原始碼包大概一至兩個月左右會更新一次,雖然不夠及時,但比起從Mercurial複製程式碼的確方便和快捷許多。筆者下載的是OpenJDK 7 Update 6 Build b21版原始碼包,2012年8月28日釋出,大概99MB,解壓後約為339MB。

。。。。。。省略5000字啥時候能有資訊編譯出來再說