什麼是HotSpot?
提起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編譯器與混合的運行時系統。 一、對象建立
虛擬機器遇到一條 new 指令時,首先將去檢查這個指令的參數是否能在常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是否已被載入、解析和初始化過。如果沒有,那必須先之行相應的類載入過程。
檢查通過後,虛擬機器為新生對象在堆中分配記憶體,對象所需要的記憶體在類載入完成就可完全確定。 如果 堆 中記憶體是絕對規整的,記憶體就會分為 空閑 和 用過的兩邊,中間放著一個指標作為分界點的指標,分配記憶體就僅僅是把那個指標向閒置空間那邊挪過一段與對象大小相等的距離,成為 “指標碰撞 (Bump the Pointer)” 如果java堆中記憶體不是規整的,虛擬機器就維護一個列表,記錄哪些記憶體塊是可用的,在分配時候從列表中找到一塊足夠大的空間劃分給對象執行個體,並更新列表上的記錄,這種分配方式稱為“空閑列表 (Free List)”。選擇哪種分配方式由java堆是否規整決定,而java堆是否規整又由所採用的垃圾收集器是否帶有壓縮整理功能決定。
虛擬機器需要將分配到的記憶體空間都初始化為零值,如果使用TLAB(本地線程分配緩衝),這一工作過程也可以提前至TLAB分配時進行。
虛擬機器要對對象進行必要的設定。必要資訊都會存放在對象的對象頭之中。
執行new指令之後會接著執行方法,把對象按照程式員的意願進行初始化。 二、對象的記憶體布局
在HotSpot虛擬機器中,對象在記憶體中儲存的布局分為:對象頭(Header)、執行個體資料(Instance Data)和對齊填充(Padding)。
對象頭包含兩部分資訊:第一部分用於儲存物件自身的運行時資料。這部分資料的長度在32位和64位的虛擬機器(未開啟壓縮指標)中分別為32bit和64bit,稱為“Mark Word”;第二部分是類型指標,即對象指向它的類別中繼資料的指標,虛擬機器通過這個指標來確定這個對象是哪個類的執行個體。如果對象是java數組,那在對象頭中還必須有一塊用於記錄數組長度的資料。
執行個體資料存放區對象真正的有效資訊,就是程式碼中定義的各種類型的欄位內容。
對齊填充並不是必然存在,也沒有特別的含義,它僅僅起著預留位置的作用。
三、對象的訪問定位
對象的訪問方式取決於虛擬機器實現而定的,目前主流的訪問方式有使用控制代碼和直接指標兩種。
使用控制代碼訪問的話,在堆中會划出一塊記憶體來作為控制代碼池,reference中儲存的就是對象的控制代碼地址,而控制代碼中包含了對象執行個體資料與類型資料各自的具體的地址資訊
使用直接指標訪問,堆對象的布局就必須考慮如何放置訪問類型資料的相關資訊,而reference中儲存的直接就是對象地址。
使用控制代碼好處就是對象移動時只會改變控制代碼中的執行個體資料指標,而reference本身不需要修改。
使用直接指標訪問方式最大好處就是速度更快。