java程式的記憶體配置設定
java 檔案編譯執行與虛拟機(jvm)介紹
java 虛拟機(jvm)是可運作java代碼的假想計算機。隻要根據jvm規格描述将解釋器移植到特定的計算機上,就能保證經過編譯的任何java代碼能夠在該系統上運作。本文首先簡要介紹從java檔案的編譯到最終執行的過程,随後對jvm規格描述作一說明。
一.java源檔案的編譯、下載下傳、解釋和執行
java應用程式的開發周期包括編譯、下載下傳、解釋和執行幾個部分。java編譯程式将java源程式翻譯為jvm可執行代碼?位元組碼。這一編譯過程同c/c++的編譯有些不同。當c編譯器編譯生成一個對象的代碼時,該代碼是為在某一特定硬體平台運作而産生的。是以,在編譯過程中,編譯程式通過查表将所有對符号的引用轉換為特定的記憶體偏移量,以保證程式運作。java編譯器卻不将對變量和方法的引用編譯為數值引用,也不确定程式執行過程中的記憶體布局,而是将這些符号引用資訊保留在位元組碼中,由解釋器在運作過程中創立記憶體布局,然後再通過查表來确定一個方法所在的位址。這樣就有效的保證了java的可移植性和安全性。
運作jvm位元組碼的工作是由解釋器來完成的。解釋執行過程分三部進行:代碼的裝入、代碼的校驗和代碼的執行。裝入代碼的工作由"類裝載器"(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解釋器程式的平台下運作。
特别說明:尊重作者的勞動成果,轉載請注明出處哦~~~http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytpo3