[深入理解Java虛擬機器]第一章 走進Java

Coding-lover發表於2015-10-03

第一章 概述

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

1.1 概述

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

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

1.2 Java技術體系

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

  • Java程式設計語言
  • 各種硬體平臺上的Java虛擬機器
  • Class檔案格式
  • Java API類庫
  • 來自商業機構和開源社群的第三方Java類庫

我們可以把Java程式設計語言、Java虛擬機器、 Java Development K i t ) ,JDK是用於支援Java程式開發的最小環境,在後面的內容中,為了講解 方 便 ,有一些地方會以JDK來代替整個Java技術體系。另 外 ,可以把Java API類庫中的Java SE API子集m*Java虛擬機器這兩部分統稱為JRE ( Java Runtime Environment ) ,JRE是支援Java 程式執行的標準環境。圖1-2展示了Java技術體系所包含的內容,以及JDK和JRE所涵蓋的範圍。

以上是根據各個組成部分的功能來進行劃分的,如果按照技術所服務的領域來劃分,或者說按照Java技術關注的重點業務領域來劃分,Java技術體系可以分為4個平臺,分別為:

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

1.3 Java發展史

從第一個Java版本誕生到現在已經有18年的時間了。滄海桑田一瞬間,轉眼18年過去 了 ,在圖1-3所展示的時間線中,我們看到JDK已經發展到了 1.7版。在這18年裡還誕生了無數和Java相關的產品、技術和標準。現在讓我們走入時間隧道,從孕育Java語言的時代開 始 ,再來回顧一下Java的發展軌跡和歷史變遷。

1991年4月,由James Gosling博士領導的綠色計劃( Green Project)開始啟動,此計劃的 目的是開發一種能夠在各種消費性電子產品(如機頂盒、冰箱、收音機等)上執行的程式架構。這個計劃的產品就是Java語言的前身: Oak (椽樹)。Oak當時在消費品市場上並不算成功,但隨著1995年網際網路潮流的興起,Oak迅速找到了最適合自己發展的市場定位並蛻變成 為Java語言。

1995年5月23日,Oak語言改名為Java , 並且在SunWorld大會上正式釋出Java 1.0版本。 Java語言第一次提出了“Write Once,Run Anywhere”的口號。

1996年1月23日, JDK 1.0釋出,Java語言有了第一個正式版本的執行環境。 JDK 1.0提供 了一個純解釋執行的Java虛擬機器實現( Sun Classic VM ) 。 JDK 1.0版本的代表技術包括:Java虛擬機器、Applet、AWT等。

1996年4月 ,10個最主要的作業系統供應商申明將在其產品中嵌入Java技術。同年9月 , 已有大約8.3萬個網頁應用了Java技術來製作。在1996年5月 底 ,Sun公司於美國舊金山舉行了首屆JavaOne大會,從此JavaOne成為全世界數百萬Java語言開發者每年一度的技術盛會。

1997年2月19日,Sun公司釋出了JDK 1 .1,Java技術的一些最基礎的支撐點(如JDBC 等 )都是在JDK 1.1版本中釋出的, JDK 1.1版的技術代表有:JAR檔案格式、JDBC、 JavaBeans、RMI。Java語法也有了一定的發展,如內部類( Inner Class )和反射( Reflection ) 都是在這個時候出現的。

直到1999年4月8日, JDK 1 .1 一共釋出了1.1.0〜1.1.8九個版本。從1.1.4之後,每個JDK)版本都有一個自己的名字(工程代號),分別為: JDK 1.1.4-Sparkler ( 寶石) 、 JDK 1.1.5- Pumpkin ( 南瓜) 、 JDK 1.1.6-Abigail ( 阿比蓋爾,女子名) 、 JDK 1.1.7-Brutus ( 布魯圖,古 羅馬政治家和將軍)和JDK 1.1.8-Chelsea ( 切爾西,城市名)。

1998年12月4日,JDK迎來了一個里程碑式的版本JDK 1.2,工程代號為Playground(競技 場 ),Sun在這個版本中把Java技術體系拆分為3個方向,分別是面向桌面應用開發的J2SE ( Java 2 Platform,Standard Edition ) 、面向企業級開發的J2EE ( Java 2 Platform,Enterprise Edition ) 和麵向手機等移動終端開發的J2ME ( Java 2 Platforn,Micro Edition )。在這個版本中出現的代表性技術非常多,如EJB、 Java Plug-in、 Java IDL、Swing等 ,並且這個版本中 Java虛擬機器第一次內建了JIT ( Just In Time ) 編譯器( JDK 1.2中曾並存過3個虛擬機器, Classic VM、 HotSpot VM和Exact VM ,其中Exact VM只在Solaris平臺出現過;後面兩個虛擬機器都是內建JIT編譯器的,而之前版本所帶的Classic VM只能以外掛的形式使用JIT編譯器)。在語 言和API級別上 ,Java新增了strictfp關鍵字與現在Java編碼之中極為常用的一系列Collections集合類。在1999年3月和7月 ,分別有JDK 1.2.1和JDK 1.2.2兩個小版本釋出。

1999年4月27日 ,HotSpot虛擬機器發布 ,HotSpot最初由一家名為“Longview Technologies”的小公司開發,因為HotSpot的優異表現,這家公司在1997年被Sun公司收購了。HotSpot虛擬機器發布時是作為JDK 1.2的附加程式提供的,後來它成為了JDK 1.3及之後所有版本的Sun JDK的預設虛擬機器。

2000年5月8日,工程代號為Kestrel (美洲紅隼)的JDK 1.3釋出, JDK 1.3相對於JDK 1.2 的改進主要表現在一些類庫上(如數學運算和新的Timer API等),JNDI服務從JDK 1.3開始 被作為一項平臺級服務提供(以前JNDI僅僅是一項擴充套件),使用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日, 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的各個部分在GPLv2 ( GNU General Public License v2 )協議下公開了原始碼 ,並建立了OpenJDK組織對這些原始碼進行獨立管理。除了極少量的產權程式碼( Encumbered Code , 這部分程式碼大多是Sun本身也無許可權進行開源處理的)外 ,OpenJDK/L 乎包括了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 SE6Update37 , 於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表示式、函數語言程式設計)、Jigsaw專案 (虛擬機器模組化支援)、動態語言支援、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 ,這項特性到目前為止依然沒有完全實現定型)、升級類載入架構等。

到目前為止, 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虛擬機器技術將會產生相當巨大的變化。

根據Oracle官方提供的資訊,JDK 1.8的第一個正式版本將於2013年9月釋出,JDK 1.8將 會提供在JDK 1.7中規劃過,但最終未能在JDK 1.7中釋出的特性,即Lambda表示式、 Jigsaw (很不幸,隨後Oracle公司又宣佈Jigsaw在JDK 1.8中依然無法完成,需要泣至JDK 1.9 ) 和JDK 1.7中未實現的一部分Coin等。

在2011年的JavaOne大會上,Oracle公司還提到了JDK 1.9的長遠規劃,希望未來的Java虛 擬機能夠管理數以GB計的Java堆,能夠更高效地與原生程式碼整合,並且令Java虛擬機器執行時儘可能少人工干預,能夠自動調節。

備註:JDK從 1.5版 本 開 始 ,官方在正式文件與宣傳上已經不再使用類似JDK 1.5的 命 名 ,只有在 程式設計師內部使用的開發版本號( Developer Version,例如java-version的輸出)中才繼續沿用 1.5、1.6、1.7的版本號,而公開版本號( Product Version)則改為JDK 5、JDK 6、JDK 7的命名方式,本書為了行文一致,所有場合統一採用開發版本號的命名方式。

1.4 Java虛擬機器發展史

上一節我們從整個Java技術的角度觀察了Java技術的發展,許多Java程式設計師都會潛意識地把它與Sun公司的HotSpot虛擬機器等同看待,也許還有一些程式設計師會注意到BEA JRockit和 IBM J9 ,但對JVM的認識不僅僅只有這些。

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

1.4.1 Sun Classic/Exact VM

以今天的視角來看 , Sun Classic VM的技術可能很原始,這款虛擬機器的使命也早已終結。但僅憑它“世界上第一款商用Java虛擬機器”的頭銜,就足夠有讓歷史記住它的理由。

1996年1月23日,Sun公司釋出JDK 1.0,Java語言首次擁有了商用的正式執行環境,這個 JDK中所帶的虛擬機器就是Classic VM。這款虛擬機器只能使用純直譯器方式來執行Java代 碼 , 如果要使用JIT編譯器 ,就必須進行外掛。但是假如外掛了JIT編譯器 ,JIT編譯器就完全接管了虛擬機器的執行系統,直譯器便不再工作了。使用者在這款虛擬機器上執行java-version命令 ,將會看到類似下面這行輸出:

java version"l.2.2"
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 ,而這款虛擬機器中相當多的技術又是來源於一款支援Selfi吾言實現“達到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-HIVM則是它們的一組參考實現。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 ) JavalnJava
JavalnJava是Sun公司於1997年〜1998年間研發的一個實驗室性質的虛擬機器,從名字就可以看出,它試圖以Java語言來實現Java語言本身的執行環境,既所謂的“元迴圈” (Meta-Circular ,是指使用語言自身來實現其執行環境)。它必須執行在另外一個宿主虛擬機器之上 ,內部沒有JIT編譯器,程式碼只能以解釋模式執行。在20世紀末主流Java虛擬機器都未能很好解決效能問題的時代,開發這種專案,其執行速度可想而知。
( 5 ) Maxine VM
Maxine VM和上面的JavalnJava非常相似,它也是一個幾乎全部以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.5 Azul 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公司開始從硬體轉向軟體,釋出了自己的ZingJVM,可以在通用x86平臺上提供接近於Vega系統的特性。

Liquid VM即是現在的JRockit VE ( Virtual Edition ),它是BEA公司開發的,可以直接執行在自家Hypervisor系統上的JRockit VM的虛擬化版本, Liquid VM不需要作業系統的支援, 或者說它自己本身實現了一個專用作業系統的必要功能,如檔案系統、網路支援等。由虛擬機器越過通用作業系統直接控制硬體可以獲得很多好處,如線上程排程時,不需要再進行核心態/使用者態的切換等,這樣可以最大限度地發揮硬體的能力,提升Java程式的執行效能。

1.4.6 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一起處於迅猛發展階段,在Android2.2中已提供即時編譯器實現,在執行效能上有了很大的提高。

1.4.7 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.
  • Moxie JVM.
  • Jikes RVM.

1.5 展望Java技術的未來

在2005年 ,Java語言誕生10週年的SunOne技術大會上,Java語言之父James Gosling做了一場題為“Java技術下一個十年”的演講。筆者不具備James Gosling博士那樣高屋建瓴的視角 ,這裡僅從Java平臺中幾個新生的但已經開始展現出蓬勃之勢的技術發展點來看一下後續 1 〜2個JDK版本內的一些很有希望的技術重點。

1.5.1 模組化

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

在未來的Java平臺中,很可能會對模組化提出語法層面的支援。早在2007年 ,Sun公司就提出過JSR-277 :Java模組系統(JavaModuleSystem),試圖建立Java平臺的模組化標準, 但受挫於以IBM公司為提 交的 JSR-291 : Java SE動態元件支援(Dynamic Component Support for Java SE , 這實際就是OSGi R4.1 ) 。 由於模組化規範主導權的重要性,Sun公司不能接受一個無法由它控制的規範,在整個Java SE 6期間都拒絕把任何模組化技術內建到JDK 之中。在Java SE 7發展初期,Sun公司再次提交了一個新的規範請求文件JSR-294 : Java程式語言中的改進模組性支援(Improved Modularity Support in the Java Programming Language ) , 儘管這個JSR仍然沒有通過,但是Sun公司已經獨立於JCP專家組在OpenJDK裡建立了 一個名 為Jigsaw ( 拼圖)的子專案來推動這個規範在Java平臺中轉變為具體的實現。Java的模組化 之爭目前還沒有結束,OSGi已經發布到R5.0版本,而Jigsaw從Java 7延遲至Java 8 ,在2012年 7月又不得不宣佈推遲到Java 9 中釋出,從這點看來,Sun在這場戰爭中處於劣勢,但無論勝利者是哪一方, Java模組化已經成為一項無法阻擋的變革潮流。

如果讀者對Java模組化之爭感興趣,可以參考《深入理解OSGi : Equinox原理、應用與最佳實踐》的第1章。

1.5.2 混合語言

當單一的Java開發已經無法滿足當前軟體的複雜需求時,越來越多基於Java虛擬機器的語言開發被應用到軟體專案中,Java平臺上的多語言混合程式設計正成為主流,每種語言都可以針對自己擅長的方面更好地解決問題。試想一下,在一個專案之中,並行處理用Clojge語言編寫 ,展示層使用JRuby/Rails , 中間層則是Java ,每個應用層都將使用不同的程式語言來完成 ,而且,介面對每一層的開發者都是透明的,各種語言之間的互動不存在任何困難,就像使用自己語言的原生API—樣方便,因為它們最終都執行在一個虛擬機器之上。

在最近的幾年裡,Clqjure、 JRuby、Groovy等新生語言的使用人數不斷增長,而執行在Java虛擬機器( JVM ) 之上的語言數量也在迅速膨脹,圖1-4中列舉了其中的一部分。這兩點證明混合程式設計在我們身邊已經有所應用並被廣泛認可。通過特定領域的語言去解決特定領域的問題是當前軟體開發應對日趨複雜的專案需求的一個方向。

除了催生出大量的新語言之外,許多已經有很長曆史的程式語言也出現了基於Java虛擬機器實現的版本,這樣使得混合程式設計對許多以前使用其他語言的“老”程式設計師也具備相當大的吸引力 ,軟體企業投入了大量資本的現有程式碼資產也能很好地保護起來。表1-1中列舉了常見語言的JVM實現版本。

對這些執行於Java虛擬機器之上、Java之外的語言,來自系統級的、底層的支援正在迅速增強,以JSR-292為核心的一系列專案和功能改進(如Da Vinci Machine專案、Nashorn引擎、InvokeDymmic指令、java.lang.nwoke包等), 動Java虛擬機器從“Java語言的虛擬機器”向“多語言虛擬機器”的方向發展。

1.5.3 多核並行

如今 ,CPU硬體的發展方向已經從高頻率轉變為多核心,隨著多核時代的來臨,軟體開發越來越關注並行程式設計的領域。早在JDK 1.5就已經引入java.util.concurrent包實現了一個粗粒度的併發框架。而JDK 1.7中加入的java.util.concurrent forkjoin包則是對這個框架的一次重要擴充。Fork/Join模式是處理並行程式設計的一個經典方法,如圖1-5所示。雖然不能解決所有的問題 ,但是在此模式的適用範圍之內,能夠輕鬆地利用多個CPU核心提供的計算資源來協作完 成一個複雜的計算任務。通過利用Fork/Join模式 ,我們能夠更加順暢地過渡到多核時代。

在Java 8中 ,將會提供Lambda支援,這將會極大改善目前Java語言不適合函數語言程式設計的現狀 ( 目前 Java 語言使用函數語言程式設計並不是不可以 ,只是會顯得很臃腫) ,函數語言程式設計的一個重要優點就是這樣的程式天然地適合並行執行,這對Java語言在多核時代繼續保持主流語言的地位有很大幫助。

另外,在平行計算中必須提及的還有OpenJDK的子專案Sumatra ,目前顯示卡的算術運算能力、並行能力已經遠遠超過了CPU ,在圖形領域以外發掘顯示卡的潛力是近幾年計算機發展的方向之一,例如C語言的CUDA。Sumatra專案就是為Java提供使用GPU ( Graphics Processing Units ) 和APU( Accelerated Processing Units ) 運算能力的工具,以運它將會直接提供Java語言層面的API,或者為Lambda和其他JVM語言提供底層的並行運算支援。

在JDK 外圍 ,也出現了專為滿足平行計算需求的計算框架,如Apache的Hadoop Map/Reduce,這是一個簡單易懂的並行框架,能夠執行在由上千個商用機器組成的大型叢集上 ,並且能以一種可靠的容錯方式並行處理TB級別的資料集。另 外 ,還出現了諸如Scala、 Clojure及Erlang等天生就具備平行計算能力的語言。

1.5.4 進一步豐富語法

Java 5曾經對Java語法進行了一次擴充,這次擴充加入了自動裝箱、泛型、動態註解、 列舉、可變長引數、遍歷迴圈等語法,使得Java語言的精確性和易用性有了很大的進步。在 Java 7 ( 由於進度壓力,許多改進已推遲至Java 8 ) 中 ,對Java語法進行了另一次大規模的擴充。 Sun ( 已被Oracle收購)專門為改進Java語法在OpenJDK中建立了Coin子專案m來統一處理對Java語法的細節修改,如二進位制數的原生支援、在switch語句中支援字串、“< > ”操作符、異常處理的改進、簡化變長引數方法呼叫、面向資源的try-catch-finally語句等都是在 Coin專案之中提交的內容。

除了Coin專案之外,在JSR-335 ( Lambda Expressions for the Java TM Programming Language ) 中定義的Lambda表示式也將對Java的語法和語言習慣產生很大的影響,面向函式方式的程式設計可能會成為主流。

1.5.5 64位虛擬機器

在幾年之前,主流的CPU就開始支援64位架構了。Java虛擬機器也在很早之前就推出了支援64位系統的版本。但Java程式執行在64位虛擬機器上需要付出比較大的額外代價:首先是記憶體問題,由於指標膨脹和各種資料型別對齊補白的原因,執行於64位系統上的Java應用需要消耗更多的記憶體,通常要比32位系統額外增加10%〜30%的記憶體消耗;其次,多個機構的測試結果顯示,64位虛擬機器的執行速度在各個測試項中幾乎全面落後於32位虛擬機器,兩者大約有15%左右的效能差距。

但是在Java EE方面,企業級應用經常需要使用超過4GB的記憶體,對於64位虛擬機器的需求是非常迫切的,但由於上述原因,許多企業應用都仍然選擇使用虛擬叢集等方式繼續在32位 虛擬機器中進行部署。Sun也注意到了這些問題,並做出了一些改善,在JDK 1.6 Update 14之 後,提供了普通物件指標壓縮功能(-XX : +UseCompressedOops,這個引數不建議顯式設定 ,建議維持預設由虛擬機器的Ergonomics機制自動開啟),在執行程式碼時,動態植入壓縮指令以節省記憶體消耗,但是開啟壓縮指標會增加執行程式碼數量,因為所有在Java堆裡的、指向Java堆內物件的指標都會被壓縮,這些指標的訪問就需要更多的程式碼才可以實現,而且並不只是讀寫欄位才受影響,在例項方法呼叫、子型別檢查等操作中也受影響,因為物件例項指向物件型別的引用也被壓縮了。隨著硬體的進一步發展,計算機終究會完全過渡到64位的時代 ,這是一件毫無疑問的事情,主流的虛擬機器應用也終究會從32位發展至64位 ,而虛擬機器對64位的支援也將會進一步完善。

相關文章