一什麼是Java虛擬機
Java虛擬機是一個想象中的機器在實際的計算機上通過軟件模擬來實現Java虛擬機有自己想象中的硬件如處理器堆棧寄存器等還具有相應的指令系統
為什麼要使用Java虛擬機
Java語言的一個非常重要的特點就是與平台的無關性而使用Java虛擬機是實現這一特點的關鍵一般的高級語言如果要在不同的平台上運行至少需要編譯成不同的目標代碼而引入Java語言虛擬機後Java語言在不同平台上運行時不需要重新編譯Java語言使用模式Java虛擬機屏蔽了與具體平台相關的信息使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節碼)就可以在多種平台上不加修改地運行Java虛擬機在執行字節碼時把字節碼解釋成具體平台上的機器指令執行
誰需要了解Java虛擬機
Java虛擬機是Java語言底層實現的基礎對Java語言感興趣的人都應對Java虛擬機有個大概的了解這有助於理解Java語言的一些性質也有助於使用Java語言對於要在特定平台上實現Java虛擬機的軟件人員Java語言的編譯器作者以及要用硬件芯片實現Java虛擬機的人來說則必須深刻理解Java虛擬機的規范另外如果你想擴展Java語言或是把其它語言編譯成Java語言的字節碼你也需要深入地了解Java虛擬機
Java虛擬機支持的數據類型
Java虛擬機支持Java語言的基本數據類型如下:
◆byte://字節有符號整數的補碼
◆short://字節有符號整數的補碼
◆int://字節有符號整數的補碼
◆long://字節有符號整數的補碼
◆float://字節IEEE單精度浮點數
◆double://字節IEEE雙精度浮點數
◆char://字節無符號Unicode字符
幾乎所有的Java類型檢查都是在編譯時完成的上面列出的原始數據類型的數據在Java執行時不需要用硬件標記操作這些原始數據類型數據的字節碼(指令)本身就已經指出了操作數的數據類型例如iaddladdfadd和dadd指令都是把兩個數相加其操作數類型別是intlongfloat和double虛擬機沒有給boolean(布爾)類型設置單獨的指令boolean型的數據是由integer指令包括integer返回來處理的boolean型的數組則是用byte數組來處理的虛擬機使用IEEE格式的浮點數不支持IEEE格式的較舊的計算機在運行Java數值計算程序時可能會非常慢
虛擬機支持的其它數據類型包括:
◆object//對一個Javaobject(對象)的字節引用
◆returnAddress//字節用於jsr/ret/jsrw/retw指令
注:Java數組被當作object處理
虛擬機的規范對於object內部的結構沒有任何特殊的要求在Sun公司的實現中對object的引用是一個句柄其中包含一對指針:一個指針指向該object的方法表另一個指向該object的數據用Java虛擬機的字節碼表示的程序應該遵守類型規定Java虛擬機的實現應拒絕執行違反了類型規定的字節碼程序Java虛擬機由於字節碼定義的限制似乎只能運行於位地址空間的機器上但是可以創建一個Java虛擬機它自動地把字節碼轉換成位的形式從Java虛擬機支持的數據類型可以看出Java對數據類型的內部格式進行了嚴格規定這樣使得各種Java虛擬機的實現對數據的解釋是相同的從而保證了Java的與平台無關性和可移植性
二Java虛擬機體系結構
Java虛擬機由五個部分組成:一組指令集一組寄存器一個棧一個無用單元收集堆(Garbagecollectedheap)一個方法區域這五部分是Java虛擬機的邏輯成份不依賴任何實現技術或組織方式但它們的功能必須在真實機器上以某種方式實現
Java指令集
Java虛擬機支持大約個字節碼每個字節碼執行一種基本的CPU運算例如把一個整數加到寄存器子程序轉移等Java指令集相當於Java程序的匯編語言
Java指令集中的指令包含一個單字節的操作符用於指定要執行的操作還有個或多個操作數提供操作所需的參數或數據許多指令沒有操作數僅由一個單字節的操作符構成
虛擬機的內層循環的執行過程如下:
do{
取一個操作符字節;
根據操作符的值執行一個動作;
}while(程序未結束)
由於指令系統的簡單性使得虛擬機執行的過程十分簡單從而有利於提高執行的效率指令中操作數的數量和大小是由操作符決定的如果操作數比一個字節大那麼它存儲的順序是高位字節優先例如一個位的參數存放時占用兩個字節其值為:
第一個字節*+第二個字節字節碼指令流一般只是字節對齊的指令tableswitch和lookup是例外在這兩條指令內部要求強制的字節邊界對齊
寄存器
Java虛擬機的寄存器用於保存機器的運行狀態與微處理器中的某些專用寄存器類似
Java虛擬機的寄存器有四種:
◆pc:Java程序計數器
◆optop:指向操作數棧頂端的指針
◆frame:指向當前執行方法的執行環境的指針
◆vars:指向當前執行方法的局部變量區第一個變量的指針
Java虛擬機
Java虛擬機是棧式的它不定義或使用寄存器來傳遞或接受參數其目的是為了保證指令集的簡潔性和實現時的高效性(特別是對於寄存器數目不多的處理器)
所有寄存器都是位的
棧
Java虛擬機的棧有三個區域:局部變量區運行環境區操作數區
()局部變量區 每個Java方法使用一個固定大小的局部變量集它們按照與vars寄存器的字偏移量來尋址局部變量都是位的長整數和雙精度浮點數占據了兩個局部變量的空間卻按照第一個局部變量的索引來尋址(例如一個具有索引n的局部變量如果是一個雙精度浮點數那麼它實際占據了索引n和n+所代表的存儲空間)虛擬機規范並不要求在局部變量中的位的值是位對齊的虛擬機提供了把局部變量中的值裝載到操作數棧的指令也提供了把操作數棧中的值寫入局部變量的指令
()運行環境區 在運行環境中包含的信息用於動態鏈接正常的方法返回以及異常傳播
◆動態鏈接
運行環境包括對指向當前類和當前方法的解釋器符號表的指針用於支持方法代碼的動態鏈接方法的class文件代碼在引用要調用的方法和要訪問的變量時使用符號動態鏈接把符號形式的方法調用翻譯成實際方法調用裝載必要的類以解釋還沒有定義的符號並把變量訪問翻譯成與這些變量運行時的存儲結構相應的偏移地址動態鏈接方法和變量使得方法中使用的其它類的變化不會影響到本程序的代碼
◆正常的方法返回
如果當前方法正常地結束了在執行了一條具有正確類型的返回指令時調用的方法會得到一個返回值執行環境在正常返回的情況下用於恢復調用者的寄存器並把調用者的程序計數器增加一個恰當的數值以跳過已執行過的方法調用指令然後在調用者的執行環境中繼續執行下去
◆異常和錯誤傳播
異常情況在Java中被稱作Error(錯誤)或Exception(異常)是Throwable類的子類在程序中的原因是:①動態鏈接錯如無法找到所需的class文件②運行時錯如對一個空指針的引用
·程序使用了throw語句
當異常發生時Java虛擬機采取如下措施:
·檢查與當前方法相聯系的catch子句表每個catch子句包含其有效指令范圍能夠處理的異常類型以及處理異常的代碼塊地址
·與異常相匹配的catch子句應該符合下面的條件:造成異常的指令在其指令范圍之內發生的異常類型是其能處理的異常類型的子類型如果找到了匹配的catch子句那麼系統轉移到指定的異常處理塊處執行;如果沒有找到異常處理塊重復尋找匹配的catch子句的過程直到當前方法的所有嵌套的catch子句都被檢查過
·由於虛擬機從第一個匹配的catch子句處繼續執行所以catch子句表中的順序是很重要的因為Java代碼是結構化的因此總可以把某個方法的所有的異常處理器都按序排列到一個表中對任意可能的程序計數器的值都可以用線性的順序找到合適的異常處理塊以處理在該程序計數器值下發生的異常情況
·如果找不到匹配的catch子句那麼當前方法得到一個未截獲異常的結果並返回到當前方法的調用者好像異常剛剛在其調用者中發生一樣如果在調用者中仍然沒有找到相應的異常處理塊那麼這種錯誤傳播將被繼續下去如果錯誤被傳播到最頂層那麼系統將調用一個缺省的異常處理塊
()操作數棧區 機器指令只從操作數棧中取操作數對它們進行操作並把結果返回到棧中選擇棧結構的原因是:在只有少量寄存器或非通用寄存器的機器(如Intel)上也能夠高效地模擬虛擬機的行為操作數棧是位的它用於給方法傳遞參數並從方法接收結果也用於支持操作的參數並保存操作的結果例如iadd指令將兩個整數相加相加的兩個整數應該是操作數棧頂的兩個字這兩個字是由先前的指令壓進堆棧的這兩個整數將從堆棧彈出相加並把結果壓回到操作數棧中
每個原始數據類型都有專門的指令對它們進行必須的操作每個操作數在棧中需要一個存儲位置除了long和double型它們需要兩個位置操作數只能被適用於其類型的操作符所操作例如壓入兩個int類型的數如果把它們當作是一個long類型的數則是非法的在Sun的虛擬機實現中這個限制由字節碼驗證器強制實行但是有少數操作(操作符dupe和swap)用於對運行時數據區進行操作時是不考慮類型的
無用單元收集堆
Java的堆是一個運行時數據區類的實例(對象)從中分配空間Java語言具有無用單元收集能力:它不給程序員顯式釋放對象的能力Java不規定具體使用的無用單元收集算法可以根據系統的需求使用各種各樣的算法
方法區
方法區與傳統語言中的編譯後代碼或是Unix進程中的正文段類似它保存方法代碼(編譯後的java代碼)和符號表在當前的Java實現中方法代碼不包括在無用單元收集堆中但計劃在將來的版本中實現每個類文件包含了一個Java類或一個Java界面的編譯後的代碼可以說類文件是Java語言的執行代碼文件為了保證類文件的平台無關性Java虛擬機規范中對類文件的格式也作了詳細的說明其具體細節請參考Sun公司的Java虛擬機規范
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26748.html