Java虛擬機器(轉)

BSDLite發表於2007-08-15
Java虛擬機器(轉)[@more@]一、 什麼是Java虛擬機器
Java虛擬機器是一個想象中的機器,在實際的計算機上透過軟體模擬來實現。Java虛擬機器有自己想象中的硬體,如處理器、堆疊、暫存器等,還具有相應的指令系統。

1.為什麼要使用Java虛擬機器?

Java語言的一個非常重要的特點就是與平臺的無關性。而使用Java虛擬機器是實現這一特點的關鍵。一般的高階語言如果要在不同的平臺上執行, 至少需要編譯成不同的目的碼。而引入Java語言虛擬機器後,Java語言在不同平臺上執行時不需要重新編譯.

Java虛擬機器遮蔽了與具體平臺相關的資訊,使得Java語言編譯程式只需生成在Java虛擬機器上執行的目的碼(位元組碼),就可以在多種平臺上不加修改地執行。Java虛擬機器在執行位元組碼時,把位元組碼解釋成具體平臺上的機器指令執行。

2.誰需要了解Java虛擬機器


Java虛擬機器是Java語言底層實現的基礎,對Java語言感興趣的人都應對Java虛擬機器有個大概的瞭解。這有助於理解Java語言的一些性質,也有助於使用Java語言。
對於要在特定平臺上實現Java虛擬機器的軟體人員,Java語言的編譯器作者以及要用硬體晶片實現Java虛擬機器的人來說,則必須深刻理解Java虛擬機器的規範。
另外,如果你想擴充套件 Java語言,或是把其它語言編譯成Java語言的位元組碼,你也需要深入地瞭解Java虛擬機器。
3.Java虛擬機器支援的資料型別

Java虛擬機器支援Java語言的基本資料型別如下:

byte://1位元組有符號整數的補碼 short://2位元組有符號整數的補碼 int://4位元組有符號整數的補碼 long://8位元組有符號整數的補碼 float://4位元組IEEE754單精度浮點數 double://8位元組IEEE754雙精度浮點數 char://2位元組無符號Unicode字元

幾乎所有的Java型別檢查都是在編譯時完成的。上面列出的原始資料型別的資料在 Java執行時不需要用硬體標記。操作這些原始資料型別資料的位元組碼(指令)本身就已經指出了運算元的資料型別,例如iadd、ladd、fadd和 dadd指令都是把兩個數相加,其運算元型別特別是int、long、float和double。
虛擬機器沒有給boolean(布林)型別設定單獨的指令。boolean型的資料是由integer指令, 包括integer返回來處理的。boolean型的陣列則是用byte陣列來處理的。
虛擬機器使用IEEE754格式的浮點數。不支援IEEE格式的較舊的計算機,在執行Java數值計算程式時,可能會非常慢。
虛擬機器支援的其它資料型別包括:

object//對一個Javaobject(物件)的4位元組引用 returnAddress//4位元組,用於jsr/ret/jsr-w/ret-w指令

注:Java陣列被當作object處理。
虛擬機器的規範對於object內部的結構沒有任何特殊的要求。在Sun公司的實現中,對 object的引用是一個控制程式碼,其中包含一對指標:一個指標指向該object的方法表,另一個指向 該object的資料。
用Java虛擬機器的位元組碼錶示的程式應該遵守型別規定。Java虛擬機器的實現應拒絕執行違反了型別規定的位元組碼程式。
Java虛擬機器由於位元組碼定義的限制似乎只能執行於32位地址空間的機器上。但是可以建立一個Java虛擬機器,它自動地把位元組碼轉換成64位的形式。
從Java虛擬機器支援的資料型別可以看出,Java對資料型別的內部格式進行了嚴格規定,這樣使得各種Java虛擬機器的實現對資料的解釋是相同的,從而保證了Java的與平臺無關性和可移植性。
二、 Java虛擬機器體系結構

Java虛擬機器由五個部分組成:一組指令集、一組暫存器、一個棧、一個無用單元收集堆(Garbage-collected-heap)、一個方法區域。這五部分是Java虛擬機器的邏輯成份,不依賴 任何實現技術或組織方式,但它們的功能必須在真實機器上以某種方式實現。

Java指令集
Java虛擬機器支援大約248個位元組碼。每個位元組碼執行一種基本的CPU運算,例如,把一個整數加到暫存器,子程式轉移等。Java指令集相當於Java程式的組合語言。
Java指令集中的指令包含一個單位元組的運算子,用於指定要執行的操作,還有0個或多個運算元,提供操作所需的引數或資料。許多指令沒有運算元,僅由一個單位元組的運算子構成。虛擬機器的內層迴圈的執行過程如下:
do{ 取一個運算子位元組; 根據運算子的值執行一個動作; }while(程式未結束)

由於指令系統的簡單性,使得虛擬機器執行的過程十分簡單,從而有利於提高執行的效率。
指令中運算元的數量和大小是由運算子決定的。如果運算元比一個位元組大,那麼它儲存的順序是高位位元組優先。例如,一個16位的引數存放時佔用兩個位元組,其值為: 第一個位元組*256+第二個位元組
位元組碼指令流一般只是位元組對齊的。指令tableswitch和lookup是例外,在這兩條指令內部 要求強制的4位元組邊界對齊。

暫存器
Java虛擬機器的暫存器用於儲存機器的執行狀態,與微處理器中的某些專用暫存器類似。 Java虛擬機器的暫存器有四種:
pc:Java程式計數器。 optop:指向運算元棧頂端的指標。 frame:指向當前執行方法的執行環境的指標。 vars:指向當前執行方法的區域性變數區第一個變數的指標。


Java虛擬機器
Java虛擬機器是棧式的,它不定義或使用暫存器來傳遞或接受引數,其目的是為了保證指令集的簡潔性和實現時的高效性(特別是對於暫存器數目不多的處理器)。所有暫存器都是32位的。


Java虛擬機器的棧有三個區域:區域性變數區、執行環境區、運算元區。
區域性變數區 
每個Java方法使用一個固定大小的區域性變數集。它們按照與vars暫存器的字偏移量來定址。區域性變數都是32位的。長整數和雙精度浮點數佔據了兩個區域性變數的空間,卻按照第一個區域性變數的索引來定址。(例如,一個具有索引n的區域性變數,如果是一個雙精度浮點數,那麼它實際佔據了索引 n和n+1所代表的儲存空間。)虛擬機器規範並不要求在區域性變數中的64位的值是64位對齊的虛擬機器提供了把區域性變數中的值裝載到運算元棧的指令,也提供了把運算元棧中的值寫入區域性變數的指令。
執行環境區
 在執行環境中包含的資訊用於動態連結,正常的方法返回以及異常傳播。
動態連結
執行環境包括對指向當前類和當前方法的直譯器符號表的指標,用於支援方法程式碼的動態連結。方法的class檔案程式碼在引用要呼叫的方法和要訪問的變數時使用符號。動態連結把符號形式的方法呼叫翻譯成實際方法呼叫,裝載必要的類以解釋還沒有定義的符號, 並把變數訪問翻譯成與這些變數執行時的儲存結構相應的偏移地址。動態連結方法和變數使得方法中使用的其它類的變化不會影響到本程式的程式碼。
正常的方法返回
如果當前方法正常地結束了,在執行了一條具有正確型別的返回指令時,呼叫的方法會得到一個返回值。
執行環境在正常返回的情況下用於恢復呼叫者的暫存器,並把呼叫者的程式計數器增加一個恰當的數值,以跳過已執行過的方法呼叫指令,然後在呼叫者的執行環境中繼續執行下去。

異常和錯誤傳播
異常情況在Java中被稱作Error(錯誤)或Exception(異常),是Throwable類的子類,在程式中出錯的原因是:①動態連結錯,如無法找到所需的class檔案。②執行時錯,如對一個空指標的引用

程式使用了throw語句。
當異常發生時,Java虛擬機器採取如下措施:
檢查與當前方法相聯絡的catch子句表。每個catch子句包含其有效指令範圍,能夠處理的異常型別,以及處理異常的程式碼塊地址。
與異常相匹配的catch子句應該符合下面的條件:造成異常的指令在其指令範圍之內 ,發生的異常型別是其能處理的異常型別的子型別。如果找到了匹配的catch子句,那麼系統轉移到指定的異常處理塊處執行;如果沒有找到異常處理塊,重複尋找匹配的catch子句的過程,直到當前方法的所有巢狀的catch子句都被檢查過。
由於虛擬機器從第一個匹配的catch子句處繼續執行,所以catch子句表中的順序是很重要的。因為Java程式碼是結構化的,因此總可以把某個方法的所有的異常處理器都按序排列到一個表中,對任意可能的程式計數器的值,都可以用線性的順序找到合適的異常處理塊,以處理在該程式計數器值下發生的異常情況。
如果找不到匹配的catch子句,那麼當前方法得到一個"未截獲異常"的結果並返回到當前方法的呼叫者,好像異常剛剛在其呼叫者中發生一樣。如果在呼叫者中仍然沒有找到相應的異常處理,那麼系 統將呼叫一個預設的異常處理塊。
運算元棧區 
機器指令只從運算元棧中取運算元,對它們進行操作,並把結果返回到棧中。選擇棧結構的原因是:在只有少量暫存器或非通用暫存器的機器(如Intel486)上,也能夠高效地模擬虛擬機器的行為。
運算元棧是32位的。它用於給方法傳遞引數,並從方法接收結果,也用於支援操作的引數,並儲存操作的結果。
例如,iadd指令將兩個整數相加。相加的兩個整數應該是運算元棧頂的兩個字。這兩個字是由先前的指令壓進堆疊的。這兩個整數將從堆疊彈出、相加,並把結果壓回到運算元棧中。每個原始資料型別都有專門的指令對它們進行必須的操作。每個運算元在棧中需要一個儲存位置,除了long和double 型,它們需要兩個位置。
運算元只能被適用於其型別的運算子所操作。例如,壓入兩個int型別的數,如果把它們當作是一個long型別的數則是非法的。在Sun的虛擬機器實現中,這個限制由位元組碼驗證器強制實行。但是,有少數操作(運算子dupe和swap),用於對執行時資料區進行操作時是不考慮型別的。
無用單元收集堆
Java的堆是一個執行時資料區,類的例項(物件)從中分配空間。Java語言具有無用單元收集能力:它不給程式設計師顯式釋放物件的能力。Java不規定具體使用的無用單元收集演算法,可以根據系統的需求使用各種各樣的演算法。

方法區
方法區與傳統語言中的編譯後程式碼或是Unix程式中的正文段類似。它儲存方法程式碼 (編譯後的java程式碼)和符號表。在當前的Java實現中,方法程式碼不包括在無用單元收集堆中,但計劃在將來的版本中實現。每個類檔案包含了一個 Java類或一個Java介面的編譯後的程式碼。可以說類檔案是 Java語言的執行程式碼檔案。為了保證類檔案的平臺無關性,Java虛擬機器規範中對類檔案的格式也作了詳細的說明。其具體細節請參考Sun公司的Java 虛擬機器規範
三、 Java類檔案(.class檔案)

每個類檔案包含了一個Java類或一個Java介面的編譯後的程式碼。可以說類檔案是Java語言的執行程式碼檔案。為了保證類檔案的平臺無關性,Java虛擬機器規範中對類檔案的格式也作了詳細的說明。其具體細節請參考Sun公司的Java虛擬機器規範。

四、 Java晶片

由於Java語言是解釋型語言,在一般的通用處理器上其執行速度比起編譯型語言要慢很多。Sun公司為了進一步推廣Java的應用,推出了 Java晶片。這些晶片可以說是Java虛擬機器的硬體實現。與通用晶片和直譯器構成的虛擬機器不同,Java晶片可以直接執行位元組碼,也就是說,位元組碼就是 Java晶片的指令集。這種用硬體實現的虛擬機器當然要比軟體模擬的虛擬機器的速度要快得多。
Sun公司計劃推出的Java晶片有三種:picoJava,mi-croJava和ultraJava。

picoJava是一個很小的Java核心晶片,其矽片面積只有25mm2。Sun公司準備向其它公司轉讓,以便其它公司可以定製自己的Java晶片,其低端產品的售價估計不到25美元。
microJava是基於picoJava的微控制器晶片,其晶片面積約為50mm2,用於通訊裝置和其它嵌入式控制裝置。Sun公司希望Java晶片可以成為推動Java發展的主要技術之一。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617542/viewspace-958002/,如需轉載,請註明出處,否則將追究法律責任。

相關文章