Java虛擬機進階之一:Java VM前世此生html
目標:java
1, Java技術體系,從兩種分類來看。編程
2, 解釋器和編譯器的概念及配合工做原理。小程序
3, 各類Java虛擬機的介紹。安全
4, JVM的趨勢:多語言混合編程。服務器
5, 64位虛擬機的優缺點及替代方案。架構
6, 如何獲取JDK源碼併發
7,Java和Java虛擬機的關係框架
前言編程語言
Java開發技術自己的一個重要優勢致使:在虛擬機層面隱藏了底層技術的複雜性以及機器與操做系統的差別性。
Java虛擬機的緣由:爲了達到給全部硬件提供一致的虛擬平臺的目的,犧牲了一些與硬件相關的性能特性。
第1章 走近Java
世界上並無完美的程序,但咱們並不所以而沮喪,由於寫程序原本就是一個不斷追求完美的過程。
1.2 Java技術體系
從廣義上講,Clojure、JRuby、Groovy等運行於Java虛擬機上的語言及其相關的程序都屬於Java技術體系中的一員。
僅從傳統意義上來看,Sun官方所定義的Java技術體系包括如下幾個組成部分:
1, Java程序設計語言
2,各類硬件平臺上的Java虛擬機
3, Class文件格式
4,Java API類庫
5,來自商業機構和開源社區的第三方Java類庫
若是按照技術所服務的領域來劃分,或者說按照Java技術關注的重點業務領域來劃分,Java技術體系能夠分爲4個平臺,分別爲: Java Card:支持一些Java小程序(Applets)運行在小內存設備(如智能卡)上的平臺。 Java ME(Micro Edition):支持Java程序運行在移動終端(手機、PDA)上的平臺,對Java API有所精簡,並加入了針對移動終端的支持,這個版本之前稱爲J2ME。 Java SE(Standard Edition):支持面向桌面級應用(如Windows下的應用程序)的Java平臺,提供了完整的Java核心API,這個版本之前稱爲J2SE。 Java EE(Enterprise Edition):支持使用多層架構的企業應用(如ERP、CRM應用)的Java平臺,除了提供Java SE API外,還對其作了大量的擴充並提供了相關的部署支持,這個版本之前稱爲J2EE。
1, Java Card
2, Java Me
3, Java SE
4, Java EE
1.3 Java發展史
這個版本中Java虛擬機第一次內置了JIT(Just In Time)編譯器(JDK 1.2中曾並存過3個虛擬機,Classic VM、HotSpot VM和Exact VM,其中Exact VM只在Solaris平臺出現過;後面兩個虛擬機都是內置JIT編譯器的,而以前版本所帶的Classic VM只能之外掛的形式使用JIT編譯器)
Q:什麼是解釋器,什麼是編譯器?
解釋器就是虛擬機將源代碼編譯成一種中間的字節碼(class文件),與機器平臺無關
編譯器就是虛擬機將源代碼編譯成和本地機器平臺相關的機器語言。
Q:什麼是JIT編譯器?
即時編譯器(Just In Time Compiler) 簡稱JIT。
JAVA程序最初是經過解釋器(Interpreter)進行解釋執行的,當JVM發現某個方法或代碼塊運行特別頻繁的時候,就會認爲這是「熱點代碼」(Hot Spot Code)。
爲了提升熱點代碼的執行效率,就會將這些「熱點代碼」編譯成與本地機器相關的機器碼,進行各個層次的優化。 完成這個任務的編譯器就是即時編譯器(JIT)。
Q:解釋器和編譯器之間是如何配合的?
一、當程序須要迅速啓動和執行的時候,解析器首先發揮做用,省去編譯的時間,當即執行。隨着時間的推移,編譯器發揮做用,把愈來愈多的代碼編譯成本地代碼,得到更高的執行效率。
二、當機器內存限制比較大,能夠用解析方式節約內存,反之能夠用編譯提高效率。
三、解析器還能夠做爲編譯器的「逃生門」。當例如加載了新類後類型結構發生變化,能夠採用逆優化,退回到解析狀態繼續執行。
Oracle公司分別從BEA和Sun中取得了目前三大商業虛擬機的其中兩個:JRockit和HotSpot,
1.4.1 Sun Classic/Exact VM
1996年1月23日,Sun公司發佈JDK 1.0,Java語言首次擁有了商用的正式運行環境,這個JDK中所帶的虛擬機就是Classic VM。這款虛擬機只能使用純解釋器方式來執行Java代碼,若是要使用JIT編譯器,就必須進行外掛。可是假如外掛了JIT編譯器,JIT編譯器就徹底接管了虛擬機的執行系統,解釋器便再也不工做了。
因爲解釋器和編譯器不能配合工做,這就意味着若是要使用編譯器執行,編譯器就不得不對每個方法、每一行代碼都進行編譯,而不管它們執行的頻率是否具備編譯的價值。基於程序響應時間的壓力,這些編譯器根本不敢應用編譯耗時稍高的優化技術,所以這個階段的虛擬機即便用了JIT編譯器輸出本地代碼,執行效率也和傳統的C/C++程序有很大差距,「Java語言很慢」的形象就是在這時候開始。
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值的穩定),這樣每次定位對象都少了一次間接查找的開銷,提高執行性能。
1.4.2 Sun HotSpot VM
HotSpot VM的熱點代碼探測能力能夠經過執行計數器找出最具備編譯價值的代碼,而後通知JIT編譯器以方法爲單位進行編譯。若是一個方法被頻繁調用,或方法中有效循環次數不少,將會分別觸發標準編譯和OSR(棧上替換)編譯動做。經過編譯器與解釋器恰當地協同工做,能夠在最優化的程序響應時間與最佳執行性能中取得平衡,並且無須等待本地代碼輸出才能執行程序,即時編譯的時間壓力也相對減少,這樣有助於引入更多的代碼優化技術,輸出質量更高的本地代碼。
在2008年和2009年,Oracle公司分別收購了BEA公司和Sun公司,這樣Oracle就同時擁有了兩款優秀的Java虛擬機:JRockit VM和HotSpot VM。Oracle公司宣佈在不久的未來(大約應在發佈JDK 8的時候)會完成這兩款虛擬機的整合工做,使之優點互補。整合的方式大體上是在HotSpot的基礎上,移植JRockit的優秀特性,譬如使用JRockit的垃圾回收器與MissionControl服務,使用HotSpot的JIT編譯器與混合的運行時系統。
1.4.4 BEA JRockit/IBM J9 VM
JRockit VM曾經號稱「世界上速度最快的Java虛擬機」(廣告詞,貌似J9 VM也這樣說過),它是BEA公司在2002年從Appeal Virtual Machines公司收購的虛擬機。BEA公司將其發展爲一款專門爲服務器硬件和服務器端應用場景高度優化的虛擬機,因爲專一於服務器端應用,它能夠不太關注程序啓動速度,所以JRockit內部不包含解析器實現,所有代碼都靠即時編譯器編譯後執行。除此以外,JRockit的垃圾收集器和MissionControl服務套件等部分的實現,在衆多Java虛擬機中也一直處於領先水平。
1.4.5 Azul VM/BEA Liquid VM
咱們平時所說起的「高性能Java虛擬機」通常是指HotSpot、JRockit、J9這類在通用平臺上運行的商用虛擬機,但其實Azul VM和BEA Liquid VM這類特定硬件平臺專有的虛擬機纔是「高性能」的武器。
1.4.6 Apache Harmony/Google Android Dalvik VM
Dalvik VM並非一個Java虛擬機,它沒有遵循Java虛擬機規範,不能直接執行Java的Class文件,使用的是寄存器架構而不是JVM中常見的棧架構。可是它與Java又有着千絲萬縷的聯繫,它執行的dex(Dalvik Executable)文件能夠經過Class文件轉化而來,使用Java語法編寫應用程序,能夠直接使用大部分的Java API等。目前Dalvik VM隨着Android一塊兒處於迅猛發展階段,在Android 2.2中已提供即時編譯器實現,在執行性能上有了很大的提升。
1.5.2 混合語言
Java平臺上的多語言混合編程正成爲主流,每種語言均可以針對本身擅長的方面更好地解決問題。
想一下,在一個項目之中,並行處理用Clojure語言編寫,展現層使用JRuby/Rails,中間層則是Java,每一個應用層都將使用不一樣的編程語言來完成,並且,接口對每一層的開發者都是透明的,各類語言之間的交互不存在任何困難,就像使用本身語言的原生API同樣方便,由於它們最終都運行在一個虛擬機之上
在最近的幾年裏,Clojure、JRuby、Groovy等新生語言的使用人數不斷增加,而運行在Java虛擬機(JVM)之上的語言數量也在迅速膨脹,圖1-4中列舉了其中的一部分。這兩點證實混合編程在咱們身邊已經有所應用並被普遍承認。經過特定領域的語言去解決特定領域的問題是當前軟件開發應對日趨複雜的項目需求的一個方向。
對這些運行於Java虛擬機之上、Java以外的語言,來自系統級的、底層的支持正在迅速加強,以JSR-292爲核心的一系列項目和功能改進(如Da Vinci Machine項目、Nashorn引擎、InvokeDynamic指令、java.lang.invoke包等),推進Java虛擬機從「Java語言的虛擬機」向「多語言虛擬機」的方向發展。
1.5.3 多核並行
早在JDK 1.5就已經引入java.util.concurrent包實現了一個粗粒度的併發框架。而JDK 1.7中加入的java.util.concurrent.forkjoin包則是對這個框架的一次重要擴充。Fork/Join模式是處理並行編程的一個經典方法,
在Java 8中,將會提供Lambda支持,這將會極大改善目前Java語言不適合函數式編程的現狀(目前Java語言使用函數式編程並非不能夠,只是會顯得很臃腫),函數式編程的一個重要優勢就是這樣的程序自然地適合並行運行,這對Java語言在多核時代繼續保持主流語言的地位有很大幫助。
1.5.5 64位虛擬機
Java虛擬機也在很早以前就推出了支持64位系統的版本。但Java程序運行在64位虛擬機上須要付出比較大的額外代價:
首先是內存問題,因爲指針膨脹和各類數據類型對齊補白的緣由,運行於64位系統上的Java應用須要消耗更多的內存,一般要比32位系統額外增長10%~30%的內存消耗;
其次,多個機構的測試結果顯示,64位虛擬機的運行速度在各個測試項中幾乎全面落後於32位虛擬機,二者大約有15%左右的性能差距。
可是在Java EE方面,企業級應用常常須要使用超過4GB的內存,對於64位虛擬機的需求是很是迫切的,但因爲上述緣由,許多企業應用都仍然選擇使用虛擬集羣等方式繼續在32位虛擬機中進行部署。
1.6 實戰:本身編譯JDK
想要一探JDK內部的實現機制,最便捷的路徑之一就是本身編譯一套JDK,經過閱讀和跟蹤調試JDK源碼去了解Java技術體系的原理,雖然門檻會高一點,但確定會比閱讀各類書籍、文章更加貼近本質。另外,JDK中的不少底層方法都是本地化(Native)的,須要跟蹤這些方法的運做或對JDK進行Hack的時候,都須要本身編譯一套JDK。
1.6.1 獲取JDK源碼
獲取OpenJDK源碼有兩種方式:
對於通常讀者,建議採用第二種方式,即直接下載官方打包好的源碼包,讀者能夠從Source Bundle Releases頁面(地址:http://jdk7.java.net/source.html)取得打包好的源碼,到本地直接解壓便可。
For MoreDetails(官方文檔):
參看官網文檔java及java vm相關部分,提到一個問題:
Q: Java 和Java虛擬機的關係
Java 虛擬機並不侷限於特定的實現技術、主機硬件和操做系統,Java 虛擬機也不侷限於特定的代碼執行方式,它不強求使用解釋器來執行程序,也能夠經過把本身的指令集編譯爲實際 CPU 的指令來實現,它能夠經過微代碼(Microcode)來實現,或者甚至直接實如今 CPU 中。
Java 虛擬機與 Java 語言並無必然的聯繫,它只與特定的二進制文件格式——Class 文件
格式所關聯,Class 文件中包含了 Java 虛擬機指令集(或者稱爲字節碼、Bytecodes)和符號表,還有一些其餘輔助信息。
基於安全方面的考慮,Java 虛擬機要求在 Class 文件中使用了許多強制性的語法和結構化
約束,但任一門功能性語言均可以表示爲一個能被 Java 虛擬機接收的有效的 Class 文件。做爲一個通用的、機器無關的執行平臺,任何其餘語言的實現者均可以將 Java 虛擬機做爲他們語言的產品交付媒介。