Java HotSpot效能引擎的體系結構 (轉)
Java HotSpot效能引擎的體系結構 (轉)[@more@]
內容
Java>TM平臺正在成為和部署的主流載體。在許多領域,Java平臺的使用率正在迅猛增長--從信用卡到大型、從網頁applets到大型商務應用。因此,Java技術的品質、成熟度和效能就成了對每一個開發人員和至關重要的因素。Sun Microsystems,Inc.正在重點投資於能夠在許多和操作面前"抬起擋路的欄杆"的技術,應用這種技術,軟體開發人員可以將基於Java的應用程式,在不考慮處理器和的情況下有效而可靠地執行。
人們對Java平臺感興趣的一個主要原因是:基於Java技術的程式與用傳統語言編寫的程式不同,它們是以一種可移植的和的形式而分佈的。過去,使用可移植的分佈形式一般來說都意味著在程式中的效能要下降。透過採用現代動態編譯技術,這種效能的下降得以減緩,其本質可說是"雙收其利"。
舉一個簡單但很重要的例子:我們可以使一個Java技術編譯器為特定版本的處理器"在執行中"生成最佳化的機器碼(例如,儘管奔騰和奔騰II處理器可以執行相同的機器碼,但沒有一種形式的機器碼可以同時對上述二者都是最佳化的)。於是,Java語言的位元組碼分佈形式不僅可以提供移植性,而且實際上還可以為效能的提高提供新的機會。
本文將介紹Java的第二代效能技術--Java HotSpot效能引擎。Java HotSpot效能引擎幾乎在其設計的每一個領域都有創新,它使用了廣泛的可用來提高效能的技術;這包括可檢測並加速效能關鍵性(performance-critical)程式碼"在執行中"的適配性最佳化技術。Java HotSpot還提供了超快速(ultra-fast)執行緒同步,以獲取執行緒安全的基於Java技術的程式的最大效能;它還提供了垃圾回收器(GC),GC不僅特別快,而且是完全"精確"的(因而也更可靠);另外,採用最新技術的演算法也減少或消除了使用者對垃圾回收而引起的暫停的感覺。最後,由於Java HotSpot效能引擎在級是以一種簡潔、高階的物件導向的設計風格編寫的,因而還進一步改善了維護性和擴充套件性。
2. 概述
下面是Java HotSpot效能引擎的主要結構性優勢:
1) 更好的一般效能
以下部分將介紹Java HotSpot效能引擎的重要的體系結構及其特性。
4. 記憶體模型
4.1 無控制程式碼物件
Java 2 軟體開發工具包(SDK)使用間接控制程式碼來表示物件的引用。雖然在垃圾回收過程中,這樣做會使物件的重新定位變得更加簡單,但這會引發一個重要的效能瓶頸,因為大多數對Java程式語言物件的例項變數的訪問都需要兩個層次的間接引用。Java HotSpot效能引擎消除了控制程式碼的概念:物件的引用被實現為直接指標,從而可提供對例項變數的C-速度訪問。垃圾回收器則負責在記憶體被回收過程中,當物件被重新定位時,尋找並所有對在適當位置上的物件的引用。
4.2 雙字(Tow-)物件頭
Java HotSpot效能引擎使用雙機器-字物件頭,而不是象Java 2 SDK那樣使用三字物件頭。由於平均的Java程式語言的物件尺寸較小,因而這種技術對節省空間產生了重要作用(大約節省了8%的堆的大小)。第一個物件頭的字包含了身份標識雜湊碼和GC狀態等資訊;第二個物件頭的字是一個對物件的類的引用。只有陣列才有第三個物件頭欄位,它是用來表示陣列大小的。
4.3 將對映資料表示為物件
類、方法以及其它內部對映資料被直接表示為堆上的物件(儘管這些物件也許不能被基於Java技術的程式所直接訪問)。這不僅簡化了記憶體模型,而且使你可以採用與回收其它Java程式語言物件相同的垃圾回收器來回收這類對映資料。
4.4 本地執行緒支援,包括任務搶先和多重處理技術
每個執行緒方法的啟用棧是使用宿主作業系統的執行緒模型來表示的。Java程式語言方法和本地方法可共享相同的棧,從而可允許在C和Java程式語言間的快速呼叫。使用宿主作業系統的執行緒排程機制可支援全搶先的Java程式語言執行緒。
使用本地作業系統的執行緒和排程機制的一個主要優點是,它能夠透明地利用本地作業系統支援多重處理。由於Java HotSpot效能引擎被設計為對在執行Java程式語言程式碼時的搶先和/或多重處理引起的競爭狀態是不敏感的,因而Java程式語言執行緒將自動利用由本地作業系統所提供的任意排程機制和處理器分配策略。
5. 記憶體垃圾回收
5.1 背景說明
Java程式語言對程式設計師的一個主要魅力在於,它是第一個可提供內建自動記憶體管理(或記憶體垃圾回收)的主流程式語言。在傳統語言中,一般都使用顯式分配/釋放模型來進行動態記憶體分配。事實證明, 這不僅是造成記憶體洩漏、程式錯誤以及用傳統語言編寫的程式崩潰的最主要原因之一,而且還是提高效能的瓶頸, 並且是形成模組化和可再使用程式碼的主要障礙(如果沒有顯式和難以理解的模組間的協同操作,在模組界限間確定釋放點有時幾乎是不可能的)。在Java程式語言中,垃圾回收也是支援安全性模型所必需的所謂"安全地"執行這一語義的重要組成部分。
當一個垃圾回收器能夠"證明"某個物件對正在執行的程式來說是不可訪問的時候,它僅透過回收該物件就可自動地在後臺處理對該物件的記憶體的"釋放"。這種自動的處理過程不僅完全消除了由於釋放太少而引起的記憶體洩漏,同時也消除了由於釋放太多而引起的程式崩潰和難以發現的引用錯誤。
從傳統上講,相對於顯式釋放模型來說, 垃圾回收一直被認為是一種沒有效率且會引起效能下降的處理過程。事實上,使用現代垃圾回收技術,可大大改善效能,且這種效能實際上要比由顯式釋放所提供的效能好得多。
5.2 Java HotSpot垃圾回收器
Java HotSpot效能引擎具有一個先進的垃圾回收器,它除了包含以下將要描述的先進技術特性外,還充分利用了簡潔和麵向物件的設計優勢,提供了一個高層次的垃圾收集結構,這個框架可被輕鬆地、使用或擴充套件以使用新的回收演算法。
以下將介紹Java HotSpot垃圾回收器的的主要特性。總體來講,所用各種技術的綜合結果無論是對需要儘可能高的效能的應用程式來說,還是對不期望有由於碎片而引起記憶體洩漏和記憶體不可訪問的長時執行應用程式來說,都是較好的。Java HotSpot效能引擎不僅能夠提供具有最新技術水平的垃圾回收器效能,而且可以保證全部記憶體回收,並完全消除記憶體碎片。
5.3 精確性
Java HotSpot垃圾回收器是一種全精確回收器, 與之形成對比的是, 許多垃圾回收器都是保守的(conservative)或半精確的(partially-accurate)。雖然保守的垃圾回收由於易於增加到一個不支援垃圾回收的系統中, 因而具有一定的吸引力, 但它卻有一定的缺陷。
一個保守的垃圾回收器不能確切地斷定所有物件的引用的分佈位置, 其結果是, 它必須保守地假設那些看似要引用一個物件的記憶體字(memory word)是事實上的物件引用。這就意味著它可能導致某種錯誤, 例如將一個整數誤認為是一個物件指標; 這會造成一些負面影響。首先, 當發生這樣的錯誤時(實際並不普遍), 記憶體洩漏會不可預知地以一種對應用程式設計師來說實質上不可再生(reproduce)或除錯(de)的方式出現(儘管由虛懸(dangling)物件引用所引起的崩潰仍可被預防, 並且如果有足夠的記憶體, 該程式仍可正確執行);第二, 由於它可能已經導致了某個錯誤, 因而一個保守的回收器必須使用控制程式碼來間接引用物件(降低效能), 或者避免重新定位物件;因為重新定位無控制程式碼物件需要更新所有對物件的引用, 這在回收器不能確切地斷定一個表面上的引用就是一個真的引用時, 是不可能做到的。不能重新定位物件將會導致物件記憶體碎片, 且更重要的是, 它會妨礙使用以下描述的先進的相繼複製回收演算法。
因為Java HotSpot回收器是全精確的, 因而它可以提供幾個有力的設計保證, 這在保守的回收器上是不可能提供的: · 所有不可訪問的物件記憶體都可以被可靠地回收;
· 所有物件都可以被重新定位, 因而可對物件記憶體的進行整理;這就消除了物件記憶體的碎片並增加了記憶體的本地性。
5.4 相繼的複製回收
Java HotSpot效能引擎採用了具有先進技術的相繼複製回收器,它有兩個主要優點:
· 與Java 2 SDK相比,為大部分程式較大地提高了分配速度和總的垃圾回收效率(通常提高了5倍);
· 相應地減小了使用者可感覺的垃圾回收時的"暫停"所出現的頻率。
相繼回收器利用了在大部分程式中大多數物件(通常為95%)都是非常短命的也就是被用作臨時資料結構這樣一個事實,透過將新建立的物件隔離到一個物件"幼稚園(nursery)"中,一個相繼回收器可以完成以下幾件事:第一,因為在物件幼稚園中,新的物件就象堆疊那樣被一個接一個地分配,因而分配變得特別的快,因為這樣它僅涉及單個指標的更新及對幼稚園的單個檢查。第二,到幼稚園溢位時,大部分幼稚園中的物件已經"死了",這就使垃圾回收器可以只簡單地將幼稚園中極少數存活的物件移到別處就可以了,從而不必對幼稚園中死去的物件做回收工作。
5.5 採用標記-整理演算法的"舊物件"回收器
儘管相繼的複製回收器可以有效地回收大部分死的物件,但較長壽命的物件仍然在"舊物件"記憶體區不斷地堆積。從記憶體不足狀態或程式要求的角度考慮,有時必須執行對舊物件的垃圾回收。Java HotSpot效能引擎可以使用一種標準的標記-整理回收演算法,它從"根"開始遍歷活物件的全部圖解,然後掃描記憶體並整理回收由死的物件遺留的縫隙。透過整理回收堆中的縫隙(而不是將它們回收到一個釋放清單中),可消除記憶體碎片;由於消除了釋放清單搜尋,則舊物件的分配將是更合理的。
5.6 增量"無暫停"垃圾回收器
標記-整理回收器不能消除所有使用者可感覺的暫停, 使用者可感覺的垃圾回收暫停是在 "舊的"物件(在機器術語中指已經 "活" 了一段時間的物件)需要做垃圾收集時出現的, 而且這種暫停與現存的活的物件的資料量成比例。這就意味著當有較多資料被處理時, 該暫停可能是任意大的; 這對伺服器應用程式、動畫或其它軟實時應用程式來說,是一種非常不好的的表現。
Java HotSpot效能引擎提供了另一種使用的舊空間垃圾回收器以解決這一問題。該回收器是全增量的, 它消除了使用者可探察的垃圾回收暫停。該增量回收器可平滑地按比例增加,即使在處理特大的物件資料集時,也可以提供相對不變的暫停時間。這為如下應用程式創造了極佳的表現:
作為一種人們十分歡迎的有益的副產品, 無暫停回收還可以改善記憶體本地性。因為該演算法試圖將緊密 "耦合的(coupled)"物件組重新定位到相鄰的記憶體區域中, 從而可以為這些物件提供最好的記憶體分頁和快取記憶體本地性之屬性。這對操作不同的物件資料集的多執行緒應用程式來說, 也是非常有益的。 6. 超快速執行緒同步
Java 程式語言的另一個重要的誘人之處,是它提供了一種語言級的執行緒同步。這就使得編寫帶有精細的執行緒同步加鎖的多執行緒程式變得十分簡單。然而不幸的是,目前的同步實現相對於其它Java程式語言中的微操作來說,效率非常底,它使精細的同步的操作變成了效能主要的瓶頸。
Java HotSpot效能引擎線上程的同步實現上取得了突破,它極大地促進了同步效能的提高。其結果是使同步效能變得如此之快,以至於對大多數現實世界的程式來說,它已經不是一個重要的效能問題了。
除了在"記憶體模型"一節中提到的在空間方面的益處之外,同步機制透過為所有無競爭的同步(它動態地由絕大多數同步所構成)提供超快速和常數-時間(constant-time)效能, 從而也提供了它的在效能方面的益處。
Java HotSpot同步實現完全適合於多重處理並應該展示出色的多處理器效能特徵。
7. Java HotSpot編譯器
7.1 背景說明
Java程式語言是一種新的具有獨特效能特徵的程式語言。迄今為止,大部分試圖提高其效能的嘗試都集中在如何應用為傳統語言開發的編譯技術上。及時編譯器是基本的快速傳統編譯器,它可以"在執行中"將Java位元組碼轉換為本地機器程式碼。及時編譯器在終端使用者的實際執行位元組碼的機器上執行,並編譯每一個被首次執行的方法。
在JIT編譯中存在著幾個問題。首先,由於編譯器是在"使用者時間"內執行於執行位元組碼的機器上,因此它將受到編譯速度的嚴格限制:如果編譯速度不是特別快,則使用者將會感到在程式的啟動或某一部分的明顯的延遲。這就不得不採取一種折衷方案,用這種折衷方案將很難進行最好的最佳化,從而將會大大地降低編譯效能。
其次,即使JIT有時間進行全最佳化,這樣的最佳化對Java程式語言來說,也比對傳統語言(如C和C++)的最佳化效果要差。這有以下幾個原因:
Java HotSpot效能引擎的體系結構透過使用適配性的最佳化技術,解決了以上所提出的Java程式語言的效能問題。適配性的最佳化技術是Sun公司的研究機構Self小組多年以來在物件導向的語言實現上的研究成果。
7.2 熱點Hot Spot檢測
適配性的最佳化技術利用了大多數程式的有趣的屬性,解決了JIT編譯問題。實際上,所有程式都是花費了它們的大部分時間而執行了它們中的很小一部分程式碼。Java HotSpot效能引擎不是在程式一啟動時就對整個程式進行編譯,而是在程式一啟動時就立即使用直譯器(interpreter)執行該程式,在執行中對該程式進行分析以檢測程式中的關鍵性"熱點(Hot Spot)",然後,再將全域性本地碼(native-code)最佳化器集中在這些熱點上。透過避免編譯(大部分程式的)不常執行的程式碼,Java HotSpot編譯器將更多的注意集中於程式的效能關鍵性部分,因而不必增加總的編譯時間。這種動態監測隨著程式的執行而不斷進行,因而,它可以精確地"在執行中"調整它的效能以適應使用者的需要。
這種方法的一個巧妙而重要的益處是,透過將編譯延遲到程式碼已被執行一會兒之後("一會兒"是指機器時間,而不是使用者時間!),從而可在程式碼被使用的過程中收集資訊,並使用這些資訊進行更智慧的最佳化。除收集程式中的熱點資訊外,也收集其它型別的資訊,如與"虛擬"方法呼叫有關的呼叫者-被呼叫者的關係資料等。
7.3 方法內嵌
正象在"背景說明"中所提到的,Java程式語言中的"虛擬"方法呼叫的出現頻率,是一個重要的妨礙最佳化的瓶頸。當Java HotSpot適配性最佳化器在執行過程中,一旦回收了有關程式"熱點"的資訊後,它不僅能將這些"熱點"編譯為原生程式碼,而且還可以執行內嵌在這些程式碼上的大量的方法。
內嵌具有重要的益處。它極大地減小了方法呼叫的動態頻率,這就節省了執行這些方法呼叫所需要的時間。而更重要的是,內嵌為最佳化器生成了大得多的程式碼塊。這種狀態可以大大地提高傳統編譯器的最佳化技術的效率,從而消除提高Java程式語言效能的障礙。
內嵌對其它程式碼的最佳化起到了促進作用,它使最佳化的效率大大提高。隨著Java HotSpot編譯器的進一步成熟,操作更大的內嵌程式碼塊的能力將使實現更先進的最佳化技術成為可能。
7.4 動態逆最佳化
儘管上述內嵌是一種非常重要的最佳化方法,但對於象Java程式語言那樣的動態的物件導向的程式語言來說,這在傳統上一直是非常難以實現的。此外,儘管檢測"熱點"和內嵌它們所呼叫的方法已經十分困難,但它仍然還不足以提供全部的Java程式語言的語義。這是因為,用Java程式語言編寫的程式不僅能夠"在執行中"改變方法呼叫的,而且能夠為一個執行的程式動態地裝載新的Java程式碼。
內嵌是基於全域性分析的,動態裝載使內嵌更加複雜了,因為它改變了一個程式內部的全域性關係。一個新的類可能包含了需要被內嵌在適當位置的新的方法。所以,Java HotSpot效能引擎必須能夠動態地逆最佳化(如果需要,然後再重新最佳化)先前已經最佳化過的"熱點",甚至在"熱點"程式碼的執行過程中進行這種操作。沒有這種能力,一般的內嵌將不能在基於Java的程式上安全地執行。
7.5 最佳化編譯器
只有效能關鍵性程式碼才被編譯,這就"購買了時間",並可將這些時間用於更好的最佳化。Java HotSpot效能引擎使用全最佳化編譯器,以此替代了相對簡單的JIT編譯器。全最佳化編譯器可執行所有第一流的最佳化。例如:死程式碼刪除、迴圈非變數的提升、普通子刪除和連續不斷的傳送(constant propagation)等。它還賦予最佳化某些特定於Java技術的效能。如:空-檢查(null-check)和值域-檢查(range-check)刪除等。暫存器分配程式(register allocator)是一個用顏色表示分配程式的全域性圖形,它充分利用了大的暫存器集(register sets)。Java HotSpot效能引擎的全最佳化編譯器的移植效能很強,它依賴相對較小的機器描述來描述目標的各個方面。儘管編譯器採用了較慢的JIT標準,但它仍然比傳統的最佳化編譯器要快得多。而且,改善的程式碼質量也是對由於減少已編譯程式碼的執行次數而節省的時間的一種"回報"。
7.6 小結
綜上所述,我們可以對Java HotSpot適配性最佳化器的作用做如下小結:
物件導向的程式語言的一個主要優勢是,透過為軟體的重複使用提供一種強大的語言機制,來增加開發的生產力。然而實際上,很少能夠獲得這種可重用性。因為大量地使用這些機制可能會極大地減損效能,因而程式設計師都必須謹慎地使用它們。Java HotSpot技術的一個驚人的副作用是,它大大地減少了這種效能的減損代價。我們相信,這將會對物件導向的軟體的開發方法產生重要的影響,它將第一次允許各個公司可以充分地使用物件導向的可重用性機制,且不會減損他們的軟體效能。
這種作用的示例很容易獲得。一個對使用Java程式語言的程式設計師的調查結果將會明確表明,許多程式設計師都避免使用全"虛擬"方法同時也避免編寫較大的方法。因為他們確信,每一個虛擬方法的呼叫都會導致效能的下降。同時,"虛擬"方法(也就是在Java程式語言中的非"static"或"final"那些方法)的精細使用對高可重用性的類的構造特別重要,因為每一個這樣的方法的作用就象一個"異常分支(hook)",它允許新的子類修改超類的操作。
由於Java HotSpot效能引擎可自動地內嵌大部分虛擬方法呼叫,因此,效能下降的程度被大大地減小了,甚至在許多情況下,被全部消除了。
無論怎樣強調這種作用的重要性都不會過分。因為使用重要的可重用性機制,可以大大地改變有關效能的權衡關係, 這種技術具有從根本上改變物件導向的程式碼的編寫方式的潛力。除此之外,隨著物件導向的程式設計方法的成熟,有一種明顯的向著更細分的物件以及更細分的方法發展的趨勢。這兩個趨勢都旨在以將來的程式碼風格,極力增加虛擬方法呼叫的頻率。隨著這種高階程式碼風格的流行,Java HotSpot技術的優勢將愈發明顯。
8. Java本地介面(JNI)支援
Java HotSpot效能引擎可用標準Java本地介面(JNI)支援本地方法。以前用JNI編寫的本地方法在原始碼和二進位制程式碼格式上都是向上相容的。初始本地方法介面將不被支援(JNI被部分地引入,因為舊的介面沒有提供對本地方法DLLs的二進位制相容性)。
HotSpot引擎的體系結構
--有關Sun的第二代效能技術的白皮書
內容
- 引言
- 概述
- 體系結構
- 記憶體模型
- 無控制程式碼(Handleless )
- 雙字物件頭
- 將對映資料表示為物件
- 本地執行緒支援,包括任務搶先和多重處理技術
- 記憶體垃圾回收
- 背景說明
- Java HotSpot垃圾回收
- 精確性
- 相繼的複製回收
- 採用標記-整理演算法的"舊物件"回收器
- 增量"無暫停"垃圾回收器
- 超快速執行緒同步
- Java HotSpot編譯器
- 背景說明
- "熱點(Hot Spot)"檢測
- 方法內嵌
- 動態逆
- 最佳化編譯器
- 小結
- 對可重用性的影響
- Java本地介面(JNI)支援
Java>TM平臺正在成為和部署的主流載體。在許多領域,Java平臺的使用率正在迅猛增長--從信用卡到大型、從網頁applets到大型商務應用。因此,Java技術的品質、成熟度和效能就成了對每一個開發人員和至關重要的因素。Sun Microsystems,Inc.正在重點投資於能夠在許多和操作面前"抬起擋路的欄杆"的技術,應用這種技術,軟體開發人員可以將基於Java的應用程式,在不考慮處理器和的情況下有效而可靠地執行。
人們對Java平臺感興趣的一個主要原因是:基於Java技術的程式與用傳統語言編寫的程式不同,它們是以一種可移植的和的形式而分佈的。過去,使用可移植的分佈形式一般來說都意味著在程式中的效能要下降。透過採用現代動態編譯技術,這種效能的下降得以減緩,其本質可說是"雙收其利"。
舉一個簡單但很重要的例子:我們可以使一個Java技術編譯器為特定版本的處理器"在執行中"生成最佳化的機器碼(例如,儘管奔騰和奔騰II處理器可以執行相同的機器碼,但沒有一種形式的機器碼可以同時對上述二者都是最佳化的)。於是,Java語言的位元組碼分佈形式不僅可以提供移植性,而且實際上還可以為效能的提高提供新的機會。
本文將介紹Java的第二代效能技術--Java HotSpot效能引擎。Java HotSpot效能引擎幾乎在其設計的每一個領域都有創新,它使用了廣泛的可用來提高效能的技術;這包括可檢測並加速效能關鍵性(performance-critical)程式碼"在執行中"的適配性最佳化技術。Java HotSpot還提供了超快速(ultra-fast)執行緒同步,以獲取執行緒安全的基於Java技術的程式的最大效能;它還提供了垃圾回收器(GC),GC不僅特別快,而且是完全"精確"的(因而也更可靠);另外,採用最新技術的演算法也減少或消除了使用者對垃圾回收而引起的暫停的感覺。最後,由於Java HotSpot效能引擎在級是以一種簡潔、高階的物件導向的設計風格編寫的,因而還進一步改善了維護性和擴充套件性。
2. 概述
下面是Java HotSpot效能引擎的主要結構性優勢:
1) 更好的一般效能
- 無控制程式碼物件(為提高速度,物件的引用被實現為直接指標);
- 更快的Java程式語言的執行緒同步;
- 為達到更快的C程式碼的調出和調入,C和Java程式碼可共享相同的啟用棧;
- 與及時編譯JIT相比較,大大減小了程式碼空間和啟動時間總開銷。
- 為獲得真原生程式碼效能,最佳化了原生程式碼編譯器;
- 適配性的"熱點(Hot Spot)"檢測主要集中於效能-關鍵性程式碼的最佳化上,從而大大減少了總編譯時間和對已編譯程式碼的記憶體需求;
- 方法內嵌技術為大部分程式消除了大多數動態方法;
- 對非內嵌方法的更快的方法呼叫。
- 更快的物件分配;
- 精確性提供了更準確的物件回收(與保守的(conservative)或半精確的(partially-accurate)那種可引起難以預料的記憶體洩漏的回收器不同);
- 相繼回收對大多數程式來說極大地提高了回收;
- 對大多數程式來說, 相繼回收還極大地減小了回收"舊的物件"而引起暫停所出現的頻率;
- 相繼回收也為使用大量"活的(live)"物件的記憶體的應用程式極大地改善了效能擴充套件性;
- 使用標記-整理(mark-compact)演算法來回收"舊的"物件,消除了記憶體碎 片,增加了本地性(locality);
- 增量"無暫停"垃圾回收器為"長壽"物件、甚至為極大量的"活"的物件在實質上消除了物件回收過程中出現的使用者可視的暫停,這對等待時間敏感的應用程式(如)以及大資料量的程式來說是理想的;
- 透明和簡檔(profiling)語意--Java HotSpot體系結構能夠使原生程式碼的生成及最佳化對程式設計師完全透明,它可以按照純位元組碼語意提供全部簡檔和除錯資訊,而不管內部實際上所用的最佳化方法。
以下部分將介紹Java HotSpot效能引擎的重要的體系結構及其特性。
4. 記憶體模型
4.1 無控制程式碼物件
Java 2 軟體開發工具包(SDK)使用間接控制程式碼來表示物件的引用。雖然在垃圾回收過程中,這樣做會使物件的重新定位變得更加簡單,但這會引發一個重要的效能瓶頸,因為大多數對Java程式語言物件的例項變數的訪問都需要兩個層次的間接引用。Java HotSpot效能引擎消除了控制程式碼的概念:物件的引用被實現為直接指標,從而可提供對例項變數的C-速度訪問。垃圾回收器則負責在記憶體被回收過程中,當物件被重新定位時,尋找並所有對在適當位置上的物件的引用。
4.2 雙字(Tow-)物件頭
Java HotSpot效能引擎使用雙機器-字物件頭,而不是象Java 2 SDK那樣使用三字物件頭。由於平均的Java程式語言的物件尺寸較小,因而這種技術對節省空間產生了重要作用(大約節省了8%的堆的大小)。第一個物件頭的字包含了身份標識雜湊碼和GC狀態等資訊;第二個物件頭的字是一個對物件的類的引用。只有陣列才有第三個物件頭欄位,它是用來表示陣列大小的。
4.3 將對映資料表示為物件
類、方法以及其它內部對映資料被直接表示為堆上的物件(儘管這些物件也許不能被基於Java技術的程式所直接訪問)。這不僅簡化了記憶體模型,而且使你可以採用與回收其它Java程式語言物件相同的垃圾回收器來回收這類對映資料。
4.4 本地執行緒支援,包括任務搶先和多重處理技術
每個執行緒方法的啟用棧是使用宿主作業系統的執行緒模型來表示的。Java程式語言方法和本地方法可共享相同的棧,從而可允許在C和Java程式語言間的快速呼叫。使用宿主作業系統的執行緒排程機制可支援全搶先的Java程式語言執行緒。
使用本地作業系統的執行緒和排程機制的一個主要優點是,它能夠透明地利用本地作業系統支援多重處理。由於Java HotSpot效能引擎被設計為對在執行Java程式語言程式碼時的搶先和/或多重處理引起的競爭狀態是不敏感的,因而Java程式語言執行緒將自動利用由本地作業系統所提供的任意排程機制和處理器分配策略。
5. 記憶體垃圾回收
5.1 背景說明
Java程式語言對程式設計師的一個主要魅力在於,它是第一個可提供內建自動記憶體管理(或記憶體垃圾回收)的主流程式語言。在傳統語言中,一般都使用顯式分配/釋放模型來進行動態記憶體分配。事實證明, 這不僅是造成記憶體洩漏、程式錯誤以及用傳統語言編寫的程式崩潰的最主要原因之一,而且還是提高效能的瓶頸, 並且是形成模組化和可再使用程式碼的主要障礙(如果沒有顯式和難以理解的模組間的協同操作,在模組界限間確定釋放點有時幾乎是不可能的)。在Java程式語言中,垃圾回收也是支援安全性模型所必需的所謂"安全地"執行這一語義的重要組成部分。
當一個垃圾回收器能夠"證明"某個物件對正在執行的程式來說是不可訪問的時候,它僅透過回收該物件就可自動地在後臺處理對該物件的記憶體的"釋放"。這種自動的處理過程不僅完全消除了由於釋放太少而引起的記憶體洩漏,同時也消除了由於釋放太多而引起的程式崩潰和難以發現的引用錯誤。
從傳統上講,相對於顯式釋放模型來說, 垃圾回收一直被認為是一種沒有效率且會引起效能下降的處理過程。事實上,使用現代垃圾回收技術,可大大改善效能,且這種效能實際上要比由顯式釋放所提供的效能好得多。
5.2 Java HotSpot垃圾回收器
Java HotSpot效能引擎具有一個先進的垃圾回收器,它除了包含以下將要描述的先進技術特性外,還充分利用了簡潔和麵向物件的設計優勢,提供了一個高層次的垃圾收集結構,這個框架可被輕鬆地、使用或擴充套件以使用新的回收演算法。
以下將介紹Java HotSpot垃圾回收器的的主要特性。總體來講,所用各種技術的綜合結果無論是對需要儘可能高的效能的應用程式來說,還是對不期望有由於碎片而引起記憶體洩漏和記憶體不可訪問的長時執行應用程式來說,都是較好的。Java HotSpot效能引擎不僅能夠提供具有最新技術水平的垃圾回收器效能,而且可以保證全部記憶體回收,並完全消除記憶體碎片。
5.3 精確性
Java HotSpot垃圾回收器是一種全精確回收器, 與之形成對比的是, 許多垃圾回收器都是保守的(conservative)或半精確的(partially-accurate)。雖然保守的垃圾回收由於易於增加到一個不支援垃圾回收的系統中, 因而具有一定的吸引力, 但它卻有一定的缺陷。
一個保守的垃圾回收器不能確切地斷定所有物件的引用的分佈位置, 其結果是, 它必須保守地假設那些看似要引用一個物件的記憶體字(memory word)是事實上的物件引用。這就意味著它可能導致某種錯誤, 例如將一個整數誤認為是一個物件指標; 這會造成一些負面影響。首先, 當發生這樣的錯誤時(實際並不普遍), 記憶體洩漏會不可預知地以一種對應用程式設計師來說實質上不可再生(reproduce)或除錯(de)的方式出現(儘管由虛懸(dangling)物件引用所引起的崩潰仍可被預防, 並且如果有足夠的記憶體, 該程式仍可正確執行);第二, 由於它可能已經導致了某個錯誤, 因而一個保守的回收器必須使用控制程式碼來間接引用物件(降低效能), 或者避免重新定位物件;因為重新定位無控制程式碼物件需要更新所有對物件的引用, 這在回收器不能確切地斷定一個表面上的引用就是一個真的引用時, 是不可能做到的。不能重新定位物件將會導致物件記憶體碎片, 且更重要的是, 它會妨礙使用以下描述的先進的相繼複製回收演算法。
因為Java HotSpot回收器是全精確的, 因而它可以提供幾個有力的設計保證, 這在保守的回收器上是不可能提供的: · 所有不可訪問的物件記憶體都可以被可靠地回收;
· 所有物件都可以被重新定位, 因而可對物件記憶體的進行整理;這就消除了物件記憶體的碎片並增加了記憶體的本地性。
5.4 相繼的複製回收
Java HotSpot效能引擎採用了具有先進技術的相繼複製回收器,它有兩個主要優點:
· 與Java 2 SDK相比,為大部分程式較大地提高了分配速度和總的垃圾回收效率(通常提高了5倍);
· 相應地減小了使用者可感覺的垃圾回收時的"暫停"所出現的頻率。
相繼回收器利用了在大部分程式中大多數物件(通常為95%)都是非常短命的也就是被用作臨時資料結構這樣一個事實,透過將新建立的物件隔離到一個物件"幼稚園(nursery)"中,一個相繼回收器可以完成以下幾件事:第一,因為在物件幼稚園中,新的物件就象堆疊那樣被一個接一個地分配,因而分配變得特別的快,因為這樣它僅涉及單個指標的更新及對幼稚園的單個檢查。第二,到幼稚園溢位時,大部分幼稚園中的物件已經"死了",這就使垃圾回收器可以只簡單地將幼稚園中極少數存活的物件移到別處就可以了,從而不必對幼稚園中死去的物件做回收工作。
5.5 採用標記-整理演算法的"舊物件"回收器
儘管相繼的複製回收器可以有效地回收大部分死的物件,但較長壽命的物件仍然在"舊物件"記憶體區不斷地堆積。從記憶體不足狀態或程式要求的角度考慮,有時必須執行對舊物件的垃圾回收。Java HotSpot效能引擎可以使用一種標準的標記-整理回收演算法,它從"根"開始遍歷活物件的全部圖解,然後掃描記憶體並整理回收由死的物件遺留的縫隙。透過整理回收堆中的縫隙(而不是將它們回收到一個釋放清單中),可消除記憶體碎片;由於消除了釋放清單搜尋,則舊物件的分配將是更合理的。
5.6 增量"無暫停"垃圾回收器
標記-整理回收器不能消除所有使用者可感覺的暫停, 使用者可感覺的垃圾回收暫停是在 "舊的"物件(在機器術語中指已經 "活" 了一段時間的物件)需要做垃圾收集時出現的, 而且這種暫停與現存的活的物件的資料量成比例。這就意味著當有較多資料被處理時, 該暫停可能是任意大的; 這對伺服器應用程式、動畫或其它軟實時應用程式來說,是一種非常不好的的表現。
Java HotSpot效能引擎提供了另一種使用的舊空間垃圾回收器以解決這一問題。該回收器是全增量的, 它消除了使用者可探察的垃圾回收暫停。該增量回收器可平滑地按比例增加,即使在處理特大的物件資料集時,也可以提供相對不變的暫停時間。這為如下應用程式創造了極佳的表現:
- 伺服器應用程式, 特別是高可用性的應用程式;
- 處理非常大的 "活的"物件的資料集的應用程式;
- 不期望有使用者可注意到的暫停的應用程式, 如遊戲、動畫或其它高互動性的應用程式。
作為一種人們十分歡迎的有益的副產品, 無暫停回收還可以改善記憶體本地性。因為該演算法試圖將緊密 "耦合的(coupled)"物件組重新定位到相鄰的記憶體區域中, 從而可以為這些物件提供最好的記憶體分頁和快取記憶體本地性之屬性。這對操作不同的物件資料集的多執行緒應用程式來說, 也是非常有益的。 6. 超快速執行緒同步
Java 程式語言的另一個重要的誘人之處,是它提供了一種語言級的執行緒同步。這就使得編寫帶有精細的執行緒同步加鎖的多執行緒程式變得十分簡單。然而不幸的是,目前的同步實現相對於其它Java程式語言中的微操作來說,效率非常底,它使精細的同步的操作變成了效能主要的瓶頸。
Java HotSpot效能引擎線上程的同步實現上取得了突破,它極大地促進了同步效能的提高。其結果是使同步效能變得如此之快,以至於對大多數現實世界的程式來說,它已經不是一個重要的效能問題了。
除了在"記憶體模型"一節中提到的在空間方面的益處之外,同步機制透過為所有無競爭的同步(它動態地由絕大多數同步所構成)提供超快速和常數-時間(constant-time)效能, 從而也提供了它的在效能方面的益處。
Java HotSpot同步實現完全適合於多重處理並應該展示出色的多處理器效能特徵。
7. Java HotSpot編譯器
7.1 背景說明
Java程式語言是一種新的具有獨特效能特徵的程式語言。迄今為止,大部分試圖提高其效能的嘗試都集中在如何應用為傳統語言開發的編譯技術上。及時編譯器是基本的快速傳統編譯器,它可以"在執行中"將Java位元組碼轉換為本地機器程式碼。及時編譯器在終端使用者的實際執行位元組碼的機器上執行,並編譯每一個被首次執行的方法。
在JIT編譯中存在著幾個問題。首先,由於編譯器是在"使用者時間"內執行於執行位元組碼的機器上,因此它將受到編譯速度的嚴格限制:如果編譯速度不是特別快,則使用者將會感到在程式的啟動或某一部分的明顯的延遲。這就不得不採取一種折衷方案,用這種折衷方案將很難進行最好的最佳化,從而將會大大地降低編譯效能。
其次,即使JIT有時間進行全最佳化,這樣的最佳化對Java程式語言來說,也比對傳統語言(如C和C++)的最佳化效果要差。這有以下幾個原因:
- Java程式語言是動態"安全的",其含義是保證程式不違反語言的語義或直接訪問非結構化記憶體。這就意味著必須經常進行動態型別測試, 例如,當轉型時(casting)和向物件陣列進行時。
- Java程式語言在"堆(heap)"上對所有物件進行分配,而在C++中,許多物件是在棧(stack)上分配的。這就意味著Java程式語言的物件分配效率比C++的物件分配效率要高得多。除此之外,由於Java程式語言是垃圾回收式的,因而它比C++有更多的不同型別的記憶體分配開銷(包括潛在的垃圾清理 (scavenging)和編寫-隔離(write-barrier)開銷)。
- 在Java程式語言中,大部分方法呼叫是"虛擬的"(潛在是多型的),這在C++中很少見。這不僅意味著方法呼叫的效能更重要,而且意味著更難以為方法呼叫而執行靜態編譯器最佳化(特別是象內嵌方法(inlining)那樣的全域性最佳化)。大多數傳統最佳化在呼叫之間是最有效的,而Java程式語言中的減小的呼叫間距離可大大降低這種最佳化的效率,這是因為它們使用了較小的程式碼段的緣故。
- 基於Java技術的程式由於其強大的動態類裝載的能力,因而可"在執行中"發生改變。這就使得它特別難於進行許多型別的全域性最佳化,因為編譯器不僅必須能夠檢測這些最佳化何時會由於動態裝載而無效,而且還必須能夠在程式執行過程中解除和/或重做這些最佳化,且不會以任何形式損壞或影響基於Java技術的程式的執行語義(即使這些最佳化涉及棧上的活動方法)。
Java HotSpot效能引擎的體系結構透過使用適配性的最佳化技術,解決了以上所提出的Java程式語言的效能問題。適配性的最佳化技術是Sun公司的研究機構Self小組多年以來在物件導向的語言實現上的研究成果。
7.2 熱點Hot Spot檢測
適配性的最佳化技術利用了大多數程式的有趣的屬性,解決了JIT編譯問題。實際上,所有程式都是花費了它們的大部分時間而執行了它們中的很小一部分程式碼。Java HotSpot效能引擎不是在程式一啟動時就對整個程式進行編譯,而是在程式一啟動時就立即使用直譯器(interpreter)執行該程式,在執行中對該程式進行分析以檢測程式中的關鍵性"熱點(Hot Spot)",然後,再將全域性本地碼(native-code)最佳化器集中在這些熱點上。透過避免編譯(大部分程式的)不常執行的程式碼,Java HotSpot編譯器將更多的注意集中於程式的效能關鍵性部分,因而不必增加總的編譯時間。這種動態監測隨著程式的執行而不斷進行,因而,它可以精確地"在執行中"調整它的效能以適應使用者的需要。
這種方法的一個巧妙而重要的益處是,透過將編譯延遲到程式碼已被執行一會兒之後("一會兒"是指機器時間,而不是使用者時間!),從而可在程式碼被使用的過程中收集資訊,並使用這些資訊進行更智慧的最佳化。除收集程式中的熱點資訊外,也收集其它型別的資訊,如與"虛擬"方法呼叫有關的呼叫者-被呼叫者的關係資料等。
7.3 方法內嵌
正象在"背景說明"中所提到的,Java程式語言中的"虛擬"方法呼叫的出現頻率,是一個重要的妨礙最佳化的瓶頸。當Java HotSpot適配性最佳化器在執行過程中,一旦回收了有關程式"熱點"的資訊後,它不僅能將這些"熱點"編譯為原生程式碼,而且還可以執行內嵌在這些程式碼上的大量的方法。
內嵌具有重要的益處。它極大地減小了方法呼叫的動態頻率,這就節省了執行這些方法呼叫所需要的時間。而更重要的是,內嵌為最佳化器生成了大得多的程式碼塊。這種狀態可以大大地提高傳統編譯器的最佳化技術的效率,從而消除提高Java程式語言效能的障礙。
內嵌對其它程式碼的最佳化起到了促進作用,它使最佳化的效率大大提高。隨著Java HotSpot編譯器的進一步成熟,操作更大的內嵌程式碼塊的能力將使實現更先進的最佳化技術成為可能。
7.4 動態逆最佳化
儘管上述內嵌是一種非常重要的最佳化方法,但對於象Java程式語言那樣的動態的物件導向的程式語言來說,這在傳統上一直是非常難以實現的。此外,儘管檢測"熱點"和內嵌它們所呼叫的方法已經十分困難,但它仍然還不足以提供全部的Java程式語言的語義。這是因為,用Java程式語言編寫的程式不僅能夠"在執行中"改變方法呼叫的,而且能夠為一個執行的程式動態地裝載新的Java程式碼。
內嵌是基於全域性分析的,動態裝載使內嵌更加複雜了,因為它改變了一個程式內部的全域性關係。一個新的類可能包含了需要被內嵌在適當位置的新的方法。所以,Java HotSpot效能引擎必須能夠動態地逆最佳化(如果需要,然後再重新最佳化)先前已經最佳化過的"熱點",甚至在"熱點"程式碼的執行過程中進行這種操作。沒有這種能力,一般的內嵌將不能在基於Java的程式上安全地執行。
7.5 最佳化編譯器
只有效能關鍵性程式碼才被編譯,這就"購買了時間",並可將這些時間用於更好的最佳化。Java HotSpot效能引擎使用全最佳化編譯器,以此替代了相對簡單的JIT編譯器。全最佳化編譯器可執行所有第一流的最佳化。例如:死程式碼刪除、迴圈非變數的提升、普通子刪除和連續不斷的傳送(constant propagation)等。它還賦予最佳化某些特定於Java技術的效能。如:空-檢查(null-check)和值域-檢查(range-check)刪除等。暫存器分配程式(register allocator)是一個用顏色表示分配程式的全域性圖形,它充分利用了大的暫存器集(register sets)。Java HotSpot效能引擎的全最佳化編譯器的移植效能很強,它依賴相對較小的機器描述來描述目標的各個方面。儘管編譯器採用了較慢的JIT標準,但它仍然比傳統的最佳化編譯器要快得多。而且,改善的程式碼質量也是對由於減少已編譯程式碼的執行次數而節省的時間的一種"回報"。
7.6 小結
綜上所述,我們可以對Java HotSpot適配性最佳化器的作用做如下小結:
- 一般來說,程式啟動得更快。這是因為,與JIT編譯器相比,預先編譯做得較少的緣故。
- 編譯過程隨著時間展開,從而使編譯暫停時間更短,更不被使用者所注意。
- 僅編譯效能關鍵性程式碼的做法"購買了時間",從而可將這些時間用在執行更好的最佳化上。
- 由於編譯較少的程式碼, 編譯程式碼所需的記憶體較少.
- 透過使編譯程式碼前的等待時間變得長一點,可收集資訊以執行更好的最佳化,如內嵌,這種技術將具有深遠的意義。
- 透過高度最佳化效能關鍵性程式碼,使重要的程式碼的執行速度更快。
物件導向的程式語言的一個主要優勢是,透過為軟體的重複使用提供一種強大的語言機制,來增加開發的生產力。然而實際上,很少能夠獲得這種可重用性。因為大量地使用這些機制可能會極大地減損效能,因而程式設計師都必須謹慎地使用它們。Java HotSpot技術的一個驚人的副作用是,它大大地減少了這種效能的減損代價。我們相信,這將會對物件導向的軟體的開發方法產生重要的影響,它將第一次允許各個公司可以充分地使用物件導向的可重用性機制,且不會減損他們的軟體效能。
這種作用的示例很容易獲得。一個對使用Java程式語言的程式設計師的調查結果將會明確表明,許多程式設計師都避免使用全"虛擬"方法同時也避免編寫較大的方法。因為他們確信,每一個虛擬方法的呼叫都會導致效能的下降。同時,"虛擬"方法(也就是在Java程式語言中的非"static"或"final"那些方法)的精細使用對高可重用性的類的構造特別重要,因為每一個這樣的方法的作用就象一個"異常分支(hook)",它允許新的子類修改超類的操作。
由於Java HotSpot效能引擎可自動地內嵌大部分虛擬方法呼叫,因此,效能下降的程度被大大地減小了,甚至在許多情況下,被全部消除了。
無論怎樣強調這種作用的重要性都不會過分。因為使用重要的可重用性機制,可以大大地改變有關效能的權衡關係, 這種技術具有從根本上改變物件導向的程式碼的編寫方式的潛力。除此之外,隨著物件導向的程式設計方法的成熟,有一種明顯的向著更細分的物件以及更細分的方法發展的趨勢。這兩個趨勢都旨在以將來的程式碼風格,極力增加虛擬方法呼叫的頻率。隨著這種高階程式碼風格的流行,Java HotSpot技術的優勢將愈發明顯。
8. Java本地介面(JNI)支援
Java HotSpot效能引擎可用標準Java本地介面(JNI)支援本地方法。以前用JNI編寫的本地方法在原始碼和二進位制程式碼格式上都是向上相容的。初始本地方法介面將不被支援(JNI被部分地引入,因為舊的介面沒有提供對本地方法DLLs的二進位制相容性)。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-991425/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 搜尋引擎的體系結構
- MySQL體系結構與儲存引擎MySql儲存引擎
- MySQL InnoDB儲存引擎體系結構MySql儲存引擎
- MySql體系結構和儲存引擎MySql儲存引擎
- java中serverlet的體系結構JavaServer
- oracle體系結構(轉)Oracle
- Oracle體系結構:記憶體結構和程式結構(轉)Oracle記憶體
- MySQL 5.6 InnoDB儲存引擎體系結構圖MySql儲存引擎
- WTL體系結構(3) (轉)
- WTL體系結構(2) (轉)
- WTL體系結構(4) (轉)
- WTL體系結構(1) (轉)
- FreeBSD DNS的體系結構(轉)DNS
- HotSpot的執行引擎-CallStub棧幀HotSpot
- Java體系結構對資訊保安的支援Java
- java知識體系結構圖Java
- FreeBSD下 DNS的體系結構(轉)DNS
- Oracle 體系結構介紹(轉)Oracle
- Software Architecture(軟體體系結構) (轉)
- 從軟體(Java/hotspot/Linux)到硬體(硬體架構)分析互斥操作的本質JavaHotSpotLinux架構
- Sqlserver儲存引擎體系結構簡介_Part1SQLServer儲存引擎
- 《MySQL 效能優化》之理解 MySQL 體系結構MySql優化
- 程式設計體系結構(02):Java異常體系程式設計Java
- 深入 Linux PAM 體系結構(轉)Linux
- Hotspot VM 執行時資料區記憶體結構劃分HotSpot記憶體
- 第一章 MySQL體系結構和儲存引擎MySql儲存引擎
- HDFS的體系結構
- [轉] Android PhoneGap Cordova 體系結構Android
- 重拾Java Web應用的基礎體系結構JavaWeb
- Oracle體系結構之-記憶體結構Oracle記憶體
- Spring的體系結構Spring
- 【PG體系結構】PG體系結構簡單說明
- [Virtualization]ESXi體系結構與記憶體管理(一)體系結構記憶體
- Oracle體系結構之-物理結構Oracle
- 論軟體體系結構的演化
- BeanFactory體系結構Bean
- 【JVM體系結構】JVM
- Servlet 體系結構Servlet