作者周志明發(fā)布于2011年7月26日
說起Java虛擬機,許多Java程序員都會潛意識地把它與Sun[1] HotSpot虛擬機等同看待,也許還有一些程序員會注意到BEA JRockit和IBM J9,但大多數(shù)人對JVM的認(rèn)識都僅限于此了。
從1996年初Sun發(fā)布的JDK 1.0中所包含的Sun ClassicVM算起,Java虛擬機已經(jīng)發(fā)展了15個年頭,滄海桑田一瞬間,15年轉(zhuǎn)眼而過,這期間曾經(jīng)涌現(xiàn)、湮滅過許多或經(jīng)典或優(yōu)秀或有特色的虛擬機實現(xiàn),在《Java虛擬機專欄》的第1篇中,我們先暫且把代碼與技術(shù)放下,一起來回顧一下Java虛擬機家族的發(fā)展軌跡和歷史變遷。
以今天的視角來看,Sun Classic VM的技術(shù)可能很原始,這款虛擬機的使命也早已終結(jié)。但僅憑它 “世界上第一款商用Java虛擬機”的頭銜,就足夠有令歷史有記住它的理由。
1996年1月23日,Sun發(fā)布JDK 1.0,Java語言首次擁有了商用的正式運行環(huán)境,這個JDK中所帶的虛擬機就是ClassicVM。這款虛擬機只能使用純解釋器方式來執(zhí)行Java代碼,如果要使用JIT編譯器那就必須進(jìn)行外掛,但是假如外掛了JIT編譯器,JIT編譯器就完全接管了虛擬機的執(zhí)行系統(tǒng),解釋器便不再工作了。用戶在這款虛擬機上執(zhí)行java –version命令,將會看到類似下面這行的輸出:
java version "1.2.2"Classic VM (build JDK-1.2.2-001, green threads, sunwjit)
其中的“sunwjit”就是Sun提供的外掛編譯器,其他類似的外掛編譯器還有SymantecJIT和shuJIT等。由于解釋器和編譯器不能配合工作,這就意味著如果要使用編譯器執(zhí)行,編譯器就不得不為對每一個方法,每一行代碼都進(jìn)行編譯,而無論它們執(zhí)行的頻率是否具有編譯的價值。基于程序響應(yīng)時間的壓力,這些編譯器根本不敢應(yīng)用編譯耗時稍高的優(yōu)化技術(shù),因此這個階段的虛擬機即使用了JIT編譯器輸出本地代碼,執(zhí)行效率也和傳統(tǒng)的C/C++程序有很大差距,“Java語言很慢”的形象就是在這時候開始在用戶心中樹立起來的。
Sun的虛擬機團隊努力去解決Classic VM所面臨的各種問題,提升運行效率,在JDK1.2時,曾在Solaris平臺上發(fā)布過一款名為ExactVM的虛擬機,它的執(zhí)行系統(tǒng)已經(jīng)具備現(xiàn)代高性能虛擬機雛形:如兩級即時編譯器、編譯器與解釋器混合工作模式等。ExactVM因它使用準(zhǔn)確式內(nèi)存管理(Exact Memory Management,也可以叫Non-Conservative/AccurateMemoryManagement)而得名,即虛擬機可以知道內(nèi)存中某個位置的數(shù)據(jù)具體是什么類型。譬如內(nèi)存中有一個32bit的整數(shù)123456,它到底是一個reference類型指向123456的內(nèi)存地址還是一個數(shù)值為123456的整數(shù),虛擬機將有能力分辨出來,這樣才能在GC的時候準(zhǔn)確判斷堆上的數(shù)據(jù)是否還可能被使用。由于使用了準(zhǔn)確式內(nèi)存管理,Exact VM可以拋棄掉以前ClassicVM基于handler的對象查找方式(原因是GC后對象將可能會被移動位置,如果地址為123456的對象移動到654321,在沒有明確信息表明內(nèi)存中哪些數(shù)據(jù)是reference的前提下,那虛擬機是不敢把內(nèi)存中所有為123456的值改成654321的,所以要使用句柄來保持reference值的穩(wěn)定),這樣每次定位對象都少了一次間接查找的開銷,提升執(zhí)行性能。
雖然Exact VM的技術(shù)相對ClassicVM來說先進(jìn)了許多,但是它命運顯得十分英雄氣短,在商業(yè)應(yīng)用上只存在了很短暫的時間就被更為優(yōu)秀的HotSpotVM所取代,甚至還沒有來得及發(fā)布Windows和Linux平臺下的商用版本。而Classic VM的生命周期則相對長了許多,它在JDK1.2之前是Sun JDK中唯一的虛擬機,在JDK 1.2時,它與HotSpot VM并存,但默認(rèn)是使用Classic VM(用戶可用java–hotspot參數(shù)切換至HotSpot VM),而在JDK 1.3時,HotSpotVM成為默認(rèn)虛擬機,它仍作為虛擬機的“備用選擇”發(fā)布(使用java –classic參數(shù)切換),直到JDK 1.4的時候,ClassicVM才正式退出商用虛擬機的歷史舞臺,與Exact VM一起進(jìn)入了Sun Labs Research VM之中。
HotSpot VM相信所有Java程序員都知道,它是SunJDK和OpenJDK中所帶的虛擬機,也是目前使用范圍最廣的Java虛擬機。但不一定所有人都知道的是,這個目前看起來“血統(tǒng)純正”的虛擬機在最初并非由Sun公司開發(fā),而是由一家名為“LongviewTechnologies”的小公司設(shè)計的;甚至這個虛擬機最初并非是為Java語言而開發(fā)的,它來源于Strongtalk語言,而虛擬機中相當(dāng)多的技術(shù)又是來源于一款支持Self語言實現(xiàn)“達(dá)到C語言50%以上的執(zhí)行效率”的目標(biāo)而設(shè)計的虛擬機,Sun公司注意到了這款虛擬機在JIT編譯上有許多優(yōu)秀的理念和實際效果,在1997年收購了Longview Technologies公司,從而獲得了HotSpot VM。
HotSpotVM既繼承了Sun之前兩款商用虛擬機的優(yōu)點(如前面提到的準(zhǔn)確式內(nèi)存管理),也有許多自己新的技術(shù)優(yōu)勢,如它名稱中的HotSpot指的就是它的熱點代碼探測技術(shù)(其實Exact VM之中也有與HotSpot幾乎一樣的熱點探測,為了Exact VM和HotSpotVM哪個成為Sun主要支持的產(chǎn)品VM,在Sun公司內(nèi)部還大吵過一場,HotSpot打敗Exact并不能算技術(shù)上的勝利),HotSpotVM的熱點代碼探測能力可以通過執(zhí)行計數(shù)器找出最具優(yōu)編譯價值的代碼,然后通知JIT編譯器以方法為單位進(jìn)行編譯。如果一個方法被頻繁調(diào)用,或方法中回邊(回邊是指程序向后跳轉(zhuǎn)的行為)次數(shù)很多,將會分別觸發(fā)標(biāo)準(zhǔn)編譯和OSR(棧上替換)編譯動作。通過編譯器與解釋器恰當(dāng)?shù)貐f(xié)同工作,可以在最優(yōu)化的程序響應(yīng)時間與最佳執(zhí)行性能中取得平衡,而且無需等待本地代碼輸出才能執(zhí)行程序,即時編譯的時間壓力也相對減小,這樣有助于引入更多的代碼優(yōu)化技術(shù),輸出質(zhì)量更高的本地代碼。
2006年的JavaOne大會上,Sun宣布最終會把Java開源,并在隨后的一年,陸續(xù)地將JDK的各個部分(其中當(dāng)然也包括了HotSpotVM)在GPL協(xié)議下公開了源碼,并在此基礎(chǔ)上建立了OpenJDK。這樣,HotSpot VM便成為了SunJDK和OpenJDK兩個實現(xiàn)極度接近的JDK項目的共同虛擬機。
在2008年和2010年,Oracle分別收購了BEA和Sun公司,這樣Oracle就同時擁有了這個星球上最優(yōu)秀的兩款Java虛擬機:JRockit VM和HotSpot VM。Oracle宣布在不久的將來(大約應(yīng)在JDK8的時候)會完成這兩款虛擬機的整合工作,使之優(yōu)勢互補。整合的方式大致上是在HotSpot的基礎(chǔ)上,移植JRockit的優(yōu)秀特性,譬如使用JRockit的垃圾回收器與MissionControl服務(wù),使用HotSpot的JIT編譯器與混合的運行時系統(tǒng)。當(dāng)HotSpot吸收了JRockit的全部功力之后,能否一統(tǒng)虛擬機的江湖,成為真正的武林盟主,我們拭目以待。
Sun公司所研發(fā)的虛擬機可不僅有前面介紹到的服務(wù)器、桌面領(lǐng)域的商用虛擬機,除此之外,Sun面對移動和嵌入式市場,也發(fā)布過虛擬機產(chǎn)品,另外還有一類虛擬機,在設(shè)計之初就沒有抱著商用的目的,僅僅是用于研究、驗證某種技術(shù)和觀點,又或者是作為一些規(guī)范的標(biāo)準(zhǔn)實現(xiàn)。這些虛擬機對于大部分不從事相關(guān)領(lǐng)域開發(fā)的Java程序員來說可能比較陌生,Sun公司發(fā)布的其他Java虛擬機有:
KVM中的K是“Kilobyte”的意思,它強調(diào)簡單,輕量,高度可移植,但是運行速度比較慢。在Androd、iOS等智能手機操作系統(tǒng)出現(xiàn)前曾經(jīng)在手機平臺上得到非常廣泛應(yīng)用。
CDC/CLDC全稱是Connected(Limited)Device Configuration,在JSR-139/JSR-218規(guī)范中進(jìn)行定義,它希望在手機、電子書、PDA等設(shè)備上建立統(tǒng)一的Java編程接口,而 CDC HotSpot VM和CLDC HotSpot VM則是它們的一組參考實現(xiàn)。CDC/CLDC是整個Java ME的重要支柱,但從目前Android和Apple iOS二分天下的移動數(shù)字設(shè)備市場看來,在這個領(lǐng)域中,Sun的虛擬機所面臨的局面遠(yuǎn)不如服務(wù)器和桌面領(lǐng)域樂觀。
Squawk VM是由Sun開發(fā),運行于Sun SPOT(Sun Small Programmable Object Technology,一種手持的Wifi設(shè)備),也曾經(jīng)運用于Java Card。這是一個Java代碼比重很高的嵌入式虛擬機實現(xiàn),其中諸如類加載器、字節(jié)碼驗證器、垃圾收集器、解釋器、編譯器和線程調(diào)度都是Java語言本 身所完成的,僅僅靠C語言來編寫設(shè)備I/O和必要的本地代碼。
JavaInJava是Sun公司1997年~1998年間所研發(fā)的一個實驗室性質(zhì)的虛擬機,從名字就可以看出,它試圖以Java語言來實 現(xiàn)Java語言本身的運行環(huán)境,既所謂的“元循環(huán)”(Meta-Circular,是指使用語言自身來實現(xiàn)其運行環(huán)境)。它必須運行在另外一個宿主虛擬機 之上,內(nèi)部沒有JIT編譯器,代碼只能以解釋模式執(zhí)行。在上世紀(jì)末主流Java虛擬機都未能很好解決性能問題的時代,開發(fā)這種項目,其執(zhí)行速度大家可想而 知。
Maxine VM和上面的JavaInJava非常相似,它也是一個幾乎全部以Java代碼實現(xiàn)(只有用于啟動JVM的加載器使用C語言編寫)的元循環(huán)Java虛擬 機。這個項目于2005年開始,到現(xiàn)在仍然在發(fā)展之中,比起JavaInJava,Maxine VM就顯得“靠譜”很多,它有先進(jìn)的JIT編譯器和垃圾收集器(但沒有解釋器),可在宿主模式或獨立模式下執(zhí)行,其執(zhí)行效率已經(jīng)接近了HotSpot Client VM的水平。
前面介紹了Sun公司的各種虛擬機,除了Sun公司以外,其他組織、公司也研發(fā)過不少虛擬機實現(xiàn),其中規(guī)模最大、最著名的就是BEA和IBM公司了。
JRockit VM曾經(jīng)號稱“世界上速度最快的Java虛擬機”(廣告詞,貌似J9VM也這樣說過),它是BEA公司在2002年從Appeal VirtualMachines公司收購獲得的虛擬機。BEA將其發(fā)展為一款專門為服務(wù)器硬件和服務(wù)端應(yīng)用場景高度優(yōu)化的虛擬機,由于專注于服務(wù)端應(yīng)用,它可以不太關(guān)注于程序啟動速度,因此JRockit內(nèi)部不包含解析器實現(xiàn),全部代碼都靠即時編譯器編譯后執(zhí)行。除此之外,JRockit的垃圾收集器和MissionControl服務(wù)套件等部分的實現(xiàn),在眾多Java虛擬機中也一直處于領(lǐng)先水平。
IBM J9VM并不是IBM公司唯一的Java虛擬機,不過是目前IBM主力發(fā)展的Java虛擬機,J9原本是內(nèi)部開發(fā)代號,正式名稱是“IBMTechnology for Java Virtual Machine”,簡稱IT4J,只是這個名字太拗口了一點,普及程度不如J9。J9VM最初是由IBMOttawa實驗室一個SmallTalk的虛擬機擴展而來的,當(dāng)時這個虛擬機有一個bug是因為8k值定義錯誤引起,工程師們花了很長時間終于發(fā)現(xiàn)并解決了這個錯誤,此后這個版本的虛擬機就被稱為K8了,后來擴展出支持Java的虛擬機就被稱為J9了。與BEAJRockit專注于服務(wù)端應(yīng)用不同,IBM J9的市場定位與SunHotSpot比較接近,它是一款設(shè)計上從服務(wù)端到桌面應(yīng)用再到嵌入式都全面考慮的多用途虛擬機,J9的開發(fā)目的是作為IBM公司各種Java產(chǎn)品的執(zhí)行平臺,它的主要市場在和IBM產(chǎn)品(如IBM WebSphere等)搭配以及在IBM AIX和z/OS這些平臺上部署Java應(yīng)用。
除了BEA和IBM外,其他一些大公司如HP、SAP等也號稱有自己的專屬JDK和虛擬機,但是它們是通過從Sun購買版權(quán)的方式獲得的,并非自己獨立開發(fā)。
我們平時所提及的“高性能Java虛擬機”一般是指HotSpot、JRockit、J9這類在通用平臺上運行的商用虛擬機,但其實Azul VM和BEA Liquid VM這類特定硬件平臺專有的虛擬機才是“高性能”的最終兵器。
Azul VM是Azul Systems 公司在HotSpot基礎(chǔ)上進(jìn)行大量改進(jìn),運行于Azul Systems公司的專有硬件Vega系統(tǒng)上的Java虛擬機,每個AzulVM實例都可以管理至少數(shù)十個CPU和數(shù)百GB的內(nèi)存的硬件資源,并提供在巨大內(nèi)存范圍內(nèi)實現(xiàn)可控的GC時間的垃圾收集器、為專有硬件優(yōu)化的線程調(diào)度等優(yōu)秀特性。在2010年,Azul開始從硬件轉(zhuǎn)向軟件,發(fā)布了自己的Zing JVM,可以在通用x86平臺上提供接近于Vega系統(tǒng)的特性。
Liquid VM是BEA公司開發(fā)的,可以直接運行在自家Hypervisor系統(tǒng)上的JRockit VM的虛擬化版本,LiquidVM不需要操作系統(tǒng)的支持,或者說它自己本身實現(xiàn)了一個專用操作系統(tǒng)的必要功能,如文件系統(tǒng)、網(wǎng)絡(luò)支持等。由虛擬機越過通用操作系統(tǒng)直接控制硬件可以獲得很多好處,如在線程調(diào)度時,不需要再進(jìn)行內(nèi)核態(tài)/用戶態(tài)的切換等,這樣可以最大限度地發(fā)揮硬件的能力,提升Java程序的執(zhí)行性能。
這節(jié)介紹的Harmony VM和Dalvik VM只能稱作“虛擬機”,而不能稱作“Java虛擬機”,但是這兩款虛擬機(以及所代表的技術(shù)體系)對最近三年的Java世界產(chǎn)生了非常大的影響和挑戰(zhàn),甚至有悲觀的評論家認(rèn)為成熟的Java生態(tài)系統(tǒng)有崩潰的可能。
Apache Harmony是一個Apache軟件基金會旗下以Apache License協(xié)議開源的實際兼容于JDK 1.5和JDK1.6的Java程序運行平臺,這個介紹相當(dāng)拗口。它包含自己的虛擬機和Java庫,用戶可以在上面運行Eclipse、Tomcat、Maven等常見的Java程序,但是……它沒有通過TCK認(rèn)證,所以我們不得不用那么一長串拗口的語言來介紹它,而不能用一句“Apache的JDK”來說明。如果一個公司要宣布自己的運行平臺“兼容于Java語言”,那就必須要通過TCK(Technology CompatibilityKit)的兼容性測試,Apache基金會曾要求Sun公司提供TCK的使用授權(quán),但是一直遭到拒絕,直到Oracle收購了Sun公司之后,雙方關(guān)系越鬧越僵,最終導(dǎo)致Apache憤然退出JCP(Java Community Process)組織,這是近代Java社區(qū)最嚴(yán)重的一次分裂。
在Sun把JDK開源形成OpenJDK之后,ApacheHarmony開源的優(yōu)勢被極大地削弱,甚至連Harmony項目的最大參與者IBM公司也宣布辭去Harmony項目管理主席的職位,參與OpenJDK項目的開發(fā)。雖然Harmony沒有真正大規(guī)模商業(yè)運用過,但是它的許多代碼(基本上是Java庫部分的代碼)被吸納進(jìn)IBM的JDK7實現(xiàn)以及Google Android SDK之中,尤其是對Android的發(fā)展起了很大推動作用。
說到Android,這個時下最熱門的移動數(shù)碼設(shè)備平臺在最近3年間的發(fā)展所取得的成果已經(jīng)遠(yuǎn)遠(yuǎn)超越了Java ME在過去十多年所獲得的成果,Android讓Java語言真正走進(jìn)了移動數(shù)碼設(shè)備領(lǐng)域,只是走的并非Sun公司原本想象的那一條路。
Dalvik VM是Android平臺的核心組成部分之一,它名字來源于冰島一個名為Dalvik的小漁村。DalvikVM并不是一個Java虛擬機,它沒有遵循Java虛擬機規(guī)范,不能直接執(zhí)行Java的class文件,使用寄存器架構(gòu)而不是JVM中常見的棧架構(gòu)。但是它與Java卻又有著千絲萬縷的聯(lián)系,它執(zhí)行dex(DalvikExecutable)文件可以通過class文件轉(zhuǎn)化而來,使用Java語法編寫應(yīng)用程序,可以直接使用大部分的JavaAPI等等。目前Dalvik VM隨著Android一起處于迅猛發(fā)展階段,在Android2.2中已提供即時編譯器實現(xiàn),執(zhí)行性能有了很大的提高。
在十幾年的Java虛擬機發(fā)展歷程中,除去上面介紹那些被大規(guī)模商業(yè)應(yīng)用過的Java虛擬機外,還有許多虛擬機是不為人知或者曾經(jīng)絢麗過但最終湮滅的。我們以其中Mircorsoft公司的JVM來介紹一下。
也許Java程序員聽起來可能會覺得驚訝,微軟曾經(jīng)是Java技術(shù)的鐵桿支持者。在Java語言誕生的初期(1996年~1998年,以JDK1.2發(fā)布之前為分界),它的主要的應(yīng)用之一是在瀏覽器中運行Java Applets程序,微軟為了在IE3中支持JavaApplets應(yīng)用而開發(fā)了自己的Java虛擬機,雖然這款虛擬機只有Windows平臺的版本(這很正常吧?),但卻是當(dāng)時Windows下性能最好的Java虛擬機,它在1997和1998連續(xù)兩年獲得了《PCMagazine》雜志的“編輯選擇獎”。但好景不長,在1997年10月,Sun公司正式以侵犯商標(biāo)、不正當(dāng)競爭等罪名控告微軟,在隨后對微軟公司的壟斷調(diào)查之中,這款虛擬機也曾作為證據(jù)之一被呈送法庭。這場官司的結(jié)果是微軟賠償2000萬美金給Sun,承諾終止其Java虛擬機的發(fā)展,并逐步在產(chǎn)品中移除Java虛擬機相關(guān)功能。
我們試想一下,如果當(dāng)年Sun沒有起訴微軟公司,微軟繼續(xù)保持著對Java技術(shù)的熱情,那Java的世界會變得更好還是更壞?.NET技術(shù)是否會發(fā)展起來?但歷史是沒有如果的。其他在本文中沒有介紹到的Java虛擬機還包括有(當(dāng)然,應(yīng)該還有很多筆者所不知道的):
本文撰寫時主要參考了以下資料:
[1] Sun與BEA分別在2010、2008年被Oracle公司收購,由于本文涉及到大量歷史事件,為了避免混亂,依然保留Sun和BEA的名稱。