java程式的執行機制

snake_hand發表於2013-03-30

(一)  Java應用程式的開發週期包括編譯、下載、解釋和執行幾個部分。Java編譯程式將 Java源程式翻譯為JVM可執行程式碼--位元組碼。這一編譯過程同C/C++的編譯有些不同。當C編譯器編譯生成一個物件的程式碼時,該程式碼是為在某一特定 硬體平臺執行而產生的。因此,在編譯過程中,編譯程式通過查表將所有對符號的引用轉換為特定的記憶體偏移量,以保證程式執行。Java編譯器卻不將對變數和 方法的引用編譯為數值引用,也不確定程式執行過程中的記憶體佈局,而是將這些符號引用資訊保留在位元組碼中,由直譯器在執行過程中創立記憶體佈局,然後再通過查 表來確定一個方法所在的地址。這樣就有效的保證了Java的可移植性和安全性。

運 行JVM位元組碼的工作是由直譯器( java命令 )來完成的。解釋執行過程分三部進行:程式碼的裝入、程式碼的校驗和程式碼的執行。裝入程式碼的工作由"類裝載器"(class loader)完成。類裝載器負責裝入執行一個程式需要的所有程式碼,這也包括程式程式碼中的類所繼承的類和被其呼叫的類。當類裝載器裝入一個類時,該類被放 在自己的名字空間中。除了通過符號引用自己名字空間以外的類,類之間沒有其他辦法可以影響其他類。在本臺計算機上的所有類都在同一地址空間內,而所有從外 部引進的類,都有一個自己獨立的名字空間。這使得本地類通過共享相同的名字空間獲得較高的執行效率,同時又保證它們與從外部引進的類不會相互影響。當裝入 了執行程式需要的所有類後,直譯器便可確定整個可執行程式的記憶體佈局。直譯器為符號引用同特定的地址空間建立對應關係及查詢表。通過在這一階段確定程式碼的 記憶體佈局,Java很好地解決了由超類改變而使子類崩潰的問題,同時也防止了程式碼對地址的非法訪問。

 

隨後,被裝入的程式碼由位元組碼校驗器進行檢查。校驗器可發現運算元棧溢位,非法資料型別轉化等多種錯誤。通過校驗後,程式碼便開始執行了。

 

Java位元組碼的執行有兩種方式:

1.即時編譯方式:直譯器先將位元組碼編譯成機器碼,然後再執行該機器碼。

2.解釋執行方式:直譯器通過每次解釋並執行一小段程式碼來完成Java位元組碼程式的所有操作。

 

通常採用的是第二種方法。由於JVM規格描述具有足夠的靈活性,這使得將位元組碼翻譯為機器程式碼的工作

具有較高的效率。對於那些對執行速度要求較高的應用程式,直譯器可將Java位元組碼即時編譯為機器碼,從而很好地保證了Java程式碼的可移植性和高效能。

(二)JVM規格描述
JVM 的設計目標是提供一個基於抽象規格描述的計算機模型,為解釋程式開發人員提很好的靈活性,同時也確保Java程式碼可在符合該規範的任何系統上執行。JVM 對其實現的某些方面給出了具體的定義,特別是對Java可執行程式碼,即位元組碼(Bytecode)的格式給出了明確的規格。這一規格包括操作碼和運算元的 語法和數值、識別符號的數值表示方式、以及Java類檔案中的Java物件、常量緩衝池在JVM的儲存映象。這些定義為JVM直譯器開發人員提供了所需的信 息和開發環境。Java的設計者希望給開發人員以隨心所欲使用Java的自由。
JVM定義了控制Java程式碼解釋執行和具體實現的五種規格,它們是:
JVM指令系統
JVM暫存器
JVM棧結構
JVM碎片回收堆
JVM儲存區
2.1JVM指令系統
JVM 指令系統同其他計算機的指令系統極其相似。Java指令也是由 操作碼和運算元兩部分組成。操作碼為8位二進位制數,運算元進緊隨在操作碼的後面,其長度根據需要而不同。操作碼用於指定一條指令操作的性質(在這裡我們採 用匯編符號的形式進行說明),如iload表示從儲存器中裝入一個整數,anewarray表示為一個新陣列分配空間,iand表示兩個整數的" 與",ret用於流程控制,表示從對某一方法的呼叫中返回。當長度大於8位時,運算元被分為兩個以上位元組存放。JVM採用了"big endian"的編碼方式來處理這種情況,即高位bits存放在低位元組中。這同 Motorola及其他的RISC CPU採用的編碼方式是一致的,而與Intel採用的"little endian "的編碼方式即低位bits存放在低位位元組的方法不同。
Java指令系統是以Java語言的實現為目的設計的,其中包含了用於呼叫方法和監視多先程系統的指令。Java的8位操作碼的長度使得JVM最多有256種指令,目前已使用了160多種操作碼。
2.2JVM指令系統
所 有的CPU均包含用於儲存系統狀態和處理器所需資訊的暫存器組。如果虛擬機器定義較多的暫存器,便可以從中得到更多的資訊而不必對棧或記憶體進行訪問,這 有利於提高執行速度。然而,如果虛擬機器中的暫存器比實際CPU的暫存器多,在實現虛擬機器時就會佔用處理器大量的時間來用常規儲存器模擬暫存器,這反而會降 低虛擬機器的效率。針對這種情況,JVM只設定了4個最為常用的暫存器。它們是:
pc程式計數器
optop運算元棧頂指標
frame當前執行環境指標
vars指向當前執行環境中第一個區域性變數的指標
所有暫存器均為32位。pc用於記錄程式的執行。optop,frame和vars用於記錄指向Java棧區的指標。
2.3JVM棧結構
作為基於棧結構的計算機,Java棧是JVM儲存資訊的主要方法。當JVM得到一個Java位元組碼應用程式後,便為該程式碼中一個類的每一個方法建立一個棧框架,以儲存該方法的狀態資訊。每個棧框架包括以下三類資訊:
區域性變數
執行環境
運算元棧
區域性變數用於儲存一個類的方法中所用到的區域性變數。vars暫存器指向該變數表中的第一個區域性變數。
執 行環境用於儲存直譯器對Java位元組碼進行解釋過程中所需的資訊。它們是:上次呼叫的方法、區域性變數指標和運算元棧的棧頂和棧底指標。執行環境是一個 執行一個方法的控制中心。例如:如果直譯器要執行iadd(整數加法),首先要從frame暫存器中找到當前執行環境,而後便從執行環境中找到運算元棧, 從棧頂彈出兩個整數進行加法運算,最後將結果壓入棧頂。
運算元棧用於儲存運算所需運算元及運算的結果。
2.4JVM碎片回收堆
Java類的例項所需的儲存空間是在堆上分配的。直譯器具體承擔為類例項分配空間的工作。直譯器在為一個例項分配完儲存空間後,便開始記錄對該例項所佔用的記憶體區域的使用。一旦物件使用完畢,便將其回收到堆中。
在 Java語言中,除了new語句外沒有其他方法為一物件申請和釋放記憶體。對記憶體進行釋放和回收的工作是由Java執行系統承擔的。這允許Java執行 系統的設計者自己決定碎片回收的方法。在SUN公司開發的Java直譯器和Hot Java環境中,碎片回收用後臺執行緒的方式來執行。這不但為執行系統提供了良好的效能,而且使程式設計人員擺脫了自己控制記憶體使用的風險。
2.5JVM儲存區
JVM 有兩類儲存區:常量緩衝池和方法區。常量緩衝池用於儲存類名稱、方法和欄位名稱以及串常量。方法區則用於儲存Java方法的位元組碼。對於這兩種存 儲區域具體實現方式在JVM規格中沒有明確規定。這使得Java應用程式的儲存佈局必須在執行過程中確定,依賴於具體平臺的實現方式。
JVM是為Java位元組碼定義的一種獨立於具體平臺的規格描述,是Java平臺獨立性的基礎。目前的JVM還存在一些限制和不足,有待於進一步的完善,但無論如何,JVM的思想是成功的。
對 比分析:如果把Java原程式想象成我們的C++原程式,Java原程式編譯後生成的位元組碼就相當於C++原程式編譯後的80x86的機器碼(二進位制程式 檔案),JVM虛擬機器相當於80x86計算機系統,Java直譯器相當於80x86CPU。在80x86CPU上執行的是機器碼,在Java直譯器上執行 的是Java位元組碼。
Java直譯器相當於執行Java位元組碼的“CPU”,但該“CPU”不是通過硬體實現的,而是用軟體實現的。Java解釋 器實際上就是特定的平臺下的 一個應用程式。只要實現了特定平臺下的直譯器程式,Java位元組碼就能通過直譯器程式在該平臺下執行,這是Java跨平臺的根本。當前,並不是在所有的平 臺下都有相應Java直譯器程式,這也是Java並不能在所有的平臺下都能執行的原因,它只能在已實現了Java直譯器程式的平臺下執行。

 

Java宣稱的一處編寫隨處執行就是由JVM來完成. 在sun的網站上你可以下載到基於各種cpu和各種作業系統的Jdk和jre的下載版本,只要尋找到合適你使用的版本,以前你所編寫的class檔案copy到其他的機器上可以直接執行,不需要再編譯.

 

其實j2se是一種規範,這種規範約定了其跨平臺執行的所需要關注很多實現,基於該規範開發人員可以任意編寫自己的Java程式碼而不需要關心這個程式可能在其他的機器和cpu上無法很好執行問題.

 

其 實你也可以看到Ibm和Weblogic都有基於j2se規範的自己實現的Java 虛擬機器 . 而且Sun所宣稱的不需要編譯而可以直接用class檔案在各個JVM上直接執行並不精確,博格曾經遇到過用sun jre開發的class檔案在ibm jre上有一個自動轉換的過程,然後這個類可以很好的工作了,幸好這種情況是自動完成,否則我們又要陷入類似於各種c c++的版本編譯器相容性問題中.

 

以下下摘錄了幾個主要的概念:

 

JVM Java Virtual Machine(Java虛擬機器),它是一個虛構出來的計算機,是通過在實際的計算機上模擬模擬各種計算機功能來實現的。 Java虛擬機器有自己完善的硬體架構,如處理器、堆疊、暫存器等,還具有相應的指令系統。JVM遮蔽了與具體作業系統平臺相關的資訊,使得Java程式只 需生成在Java虛擬機器上執行的目的碼(位元組碼),就可以在多種平臺上不加修改地執行。Java虛擬機器在執行位元組碼時,實際上最終還是把位元組碼解釋成具 體平臺上的機器指令執行。

 

JRE Java Runtime Environment(Java執行環境),執行JAVA程式所必須的環境的集合,包含JVM標準實現及Java核心類庫。

 

JSDK Java Software Development Kit,和JDK以及J2SE等同。

 

JDK Java Development Kit(Java開發工具包):包括執行環境、編譯工具及其它工具、原始碼等,基本上和J2SE等同。

 

J2ME Java 2 Micro Edition(JAVA2精簡版)API規格基於J2SE ,但是被修改為可以適合某種產品的單一要求。J2ME使JAVA 程式可以很方便的應用於電話卡、尋呼機等小型裝置,它包括兩種型別的元件,即配置(configuration)和描述(profile)。

 

J2EE Java 2 Enterprise Edition(JAVA2企業版),使用Java進行企業開發的一套擴充套件標準,必須基於J2SE,提供一個基於元件設計、開發、集合、展開企業應用的途 徑。J2EE 平臺提供了多層、分散式的應用模型,重新利用元件的能力,統一安全的模式以及靈活的處理控制能力。 J2EE包括EJB, JTA, JDBC, JCA, JMX, JNDI, JMS, JavaMail, Servlet, JSP等規範。

 

J2SE Java 2 Standard Edition(JAVA2標準版),用來開發Java程式的基礎,包括編譯器、小工具、執行環境,SUN釋出的標準版本中還包括核心類庫的所有原始碼。

相關文章