偷懶沒有上傳圖片和表格,損失了一些內容
一、 虛擬機的概述
Java虛擬機和Java API一起組成了一個“平臺”。Java平臺扮演了一個運行時Java程序與其下的硬件和操作系統之間的緩衝角色。
Java虛擬機的主要任務實裝載class文件並且執行其中的字解碼。虛擬機是實現平臺無關的關鍵。
Java語言使用Java虛擬機屏蔽了與具體平臺相關的信息,使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就可以在多種平臺上不加修改地運行。Java虛擬機在執行字節碼時,把字節碼解釋成具體平臺上的機器指令執行。
二、 各部件的功能
Class Loaders:class loaders用來從各種sources例如當地文件系統和網絡,動態的載入應用程序和類庫。
Native Interface:本地接口允許允虛擬機在應用程序和類庫中調用非java例程(routines)。
Execution Engine:執行引擎是虛擬機的核心。它執行通過class loaders載入的字解碼指令。存在各種類型的執行引擎,例如:解釋器和 just-in-time編譯器。
Memory Manager:內存管理爲對象實例提供了一個垃圾回收堆(garbage collected heap),並管理用來存儲其它內部虛擬機數據結構的內存。
Services:這個部件由爲標準類庫特性例如threads和reflection提供必要內部虛擬機支持的子部件的一個集合(collection)組成。
三、 Java虛擬機的結構
Java虛擬機是一個想象中的機器,在實際的計算機上通過軟件模擬來實現。Java虛擬機有自己想象中的硬件,如處理器、堆棧、寄存器等,還具有相應的指令系統。
Java數據分爲兩種類型:primitive types 和reference。
Reference有三種數據類型: class,array,和interface。
在Java虛擬機中,最基本的數據單元就是字(word)。字長必須足夠大,至少一個字單元就足以保存所有除long和double類型之外類型的值。它僅僅是虛擬機實現的內部屬性
四、 Runtime Data Areas
Java虛擬機在一個程序執行的時候定義了不同的數據區域。
The pc Register
每一個Java虛擬機線程有它自己的pc(program counter)寄存器。在任何一個時間點,每個Java虛擬機線程只執行一個方法的代碼,即該線程的當前方法。如果該方法不是native,也有說指向下一條將被執行的指令。如果是natvie,pc寄存器是不確定的。
五、 Java虛擬機棧
每一個Java虛擬機線程有一個私有的Java虛擬機棧,它和線程同時被創建。該棧存儲frames。該棧用來保存局部變量和中間結果,方法調用和返回時也起作用。
而本地方法調用的狀態,則是以某種依賴於具體實現的方式存儲在本地方法棧中,也可能是在寄存器或者其它某些與特定實現相關的內存區中。
Java虛擬機是棧式的,它不定義或使用寄存器來傳遞或接受參數,其目的是爲了保證指令集的簡潔性和實現時的高效性
六、 堆
Java虛擬機有一個被所有Java虛擬機線程共享的堆。堆是運行時間數據區域,所有類實例化和數組所需空間都從那分配。虛擬機啓動時堆就被創建。對象的堆存儲空間是被一個自動存儲管理系統即garbage collector回收,對象不會顯性釋放。
七、 方法區域
Java虛擬機有一個被所有Java虛擬機線程共享的方法區域。它存儲了每個類結構例如:運行時常數池(runtime constant pool),域(field),靜態數據,方法和構造函數的代碼。 方法區與傳統語言中的編譯後代碼或是Unix進程中的正文段類似。
八、 運行時常數量池
虛擬機必須爲每個被裝載的類型維護一個常量池。它包含幾種類型的常數,從編譯時已經知道的數字文字(numeric literals)到必須在運行時解析的方法和域的引用。運行時常數池的功能就像傳統編程語言中的符號表一樣,不過它包含了更廣的數據範圍。
每一個運行時常數池都從Java虛擬機的方法區域分配。
Java源代碼中所有的字符串文字最終都作爲入口存儲於常量池中。Java虛擬機把所有具有相同字符順序的字符串文字處理爲同一個String對象。
九、 Frames
frame用來存儲數據和中間結果,也用來執行動態連接(常量池解析),方法返回值和發送異常。虛擬機的實現者還可以將其他信息放入幀數據區,如用於調試的數據等。
一個方法被調用時創建一個新的frame。Frames從創建frame的線程的Java虛擬機stack的空間分配。每一個frame有自己的局部變量數組,自己的操作數棧和當前方法的類的運行時常數池的一個引用。在任何一個線程的任意點,只有一個frame,即當前正被執行的方法的frame是激活的。這個frame被稱爲當前frame,而它的方法被稱爲當前方法。
十、 局部變量區
每個frame包含一個它的局部變量的數組。
局部變量區包含對應方法的參數和局部變量。編譯器首先按聲明順序把這些參數放入局部變量數組。而對於真正的局部變量,它可以任意決定放置順序。
長整數和雙精度浮點數佔據了兩個局部變量的空間,卻按照第一個局部變量的索引來尋址。
Java虛擬機用局部變量在方法調用時傳遞參數。類方法調用時,索引從0開始。實例方法調用時,0索引對應的局部變量總是用來傳遞該實例方法所在對象的一個引用。
十一、 操作數棧
操作數棧也是被組織成一個以字長爲單位的數組。和局部變量區不同的是,它不是通過索引來訪問,而是通過標準的棧操作來訪問的。
Java虛擬機提供載入常數或者局部變量的值或者fields到操作數棧的指令。操作數棧也被用來準備將被傳遞給方法的參數和接收方法結果。
十二、 本地方法棧
任何本地方法接口都會使用某種本地方法棧。當調用本地方法時,虛擬機會保持Java棧不變,虛擬機只是簡單地動態連接並直接調用本地方法。如果某個虛擬機實現的本地方法接口是C連接模型的話,那麼它的本地方法棧就是C棧。
很可能本地方法接口需要回調Java虛擬機中的Java方法,在這種情況下,該線程會保存本地方法棧的狀態並進入到另一個Java棧。
十三、 對象的實現
對每個被裝載的類型,虛擬機都會在方法區中存儲一些類型信息:類型的全限定名 ,超類的全限定名 ,是類類型還是接口類型 ,任何直接超接口的全限定名的有序列表 等等。
如果某個方法不是抽象的和本地的,方法信息還必須保存:1、方法的字節碼 2、異常表3、操作數棧和該方法的棧幀中的局部變量區的大小。
對於每一個被裝載的類型(不管是類還是接口),虛擬機都會相應地爲它創建一個java.lang.Class類的實例,而且虛擬機還必須把這個實例和存儲在方法區中的類型數據關聯起來。
十四、 數組對象
數組也擁有一個與它們的類相關聯的Class類實例,所有具有相同維度和類型的數組都是同一個類的實例,而不管數組的長度是多少。數組的長度只與實例數據有關。
數組類的名稱有兩部分組成:每一維用一個方括號“[”表示,用字符或者字符串表示元素類型。比如:一維int數組的類名爲“[i”。
對於多維數組被表示爲數組的數組了。比如,int類型的二維數組,將表示爲一個一維數組,其中的每個元素是一個一維int數組的引用。
舉例: int[2][2] 堆中存在3個對象實例(一個[[i和2個[i對象實例),方法區中保存了“[[i”和“[i”類型信息。
十五、 Exception
在Java虛擬機中,方法的每一個catch子句是用一個異常handler表示的。每一個異常handler描述了實現那個方法的Java虛擬機碼的exception handler處於激活的偏移範圍, 也描述了該exception handler能夠處理的異常的類型,描述了將要處理那個異常的代碼的位置。
如果導致異常的指令的偏移在那個exception handler的偏移範圍內且異常類型是同一個類或者是exception handler處理的異常的類的子類的話,我們就說一個異常匹配一個exception handler 。
當一個異常被拋出來的時候,Java虛擬機在當前方法中搜索一個匹配的exception handler。
十六、 Finally子句
子節碼中的finally子句在方法內部的表現很象“微型子程序”。Java虛擬機在每個try語句塊和與其相關的catch子句的結尾處都會“調用”finally子句的子例程。Finally子句結束後(這裏的結束指的是finally子句最後一條語句正常執行完畢,但不包括拋出異常,或執行return等情況),隸屬於這個finally子句的微型子例程執行“返回”操作。程序在第一次調用微型子例程的地方繼續執行後面的語句。
如果在try、catch塊中有一條return語句,這條語句將會在finally塊執行之後才被執行。如果在finally塊中有一條return語句返回一個值,那麼這個值將被返回,而任何前面的return語句返回的值都無用。
不要依賴及時終結(finalization)來達到程序的正確性。 Finalization被調用的時間是不確定的。
同理,也不能依賴線程的優先級來達到程序的正確性。
十七、 Class文件格式
一個class文件是由8位的字節流組成。
一個class文件由單個ClassFile structure組成。
ClassFile {
u4 magic;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 super_class; //指向常量池表的一個有效索引
u2 fields_count;
field_info fields[fields_count];
…………
}
constant_pool[]
常數池是一個表示各種字符串常量,類和接的口名字,域名,和ClassFile結構與它的子結構所中引用的其它常量的表結構。
methods[]
方法表中的每一個值必須是這個類或者接口中的方法的一個method_info結構體。如果這個方法不是本地或者抽象的,那麼還需要提供實現這個方法的Java虛擬機指令。
十八、 Java的安全機制
• 沙箱的基本組件如下四個:類裝載器結構,class文件檢驗器,內置於Java虛擬機(及語言)的安全特性,安全管理器及Java API。
• Java安全模型的前三個組成部分—類裝載器體系結構、class文件檢驗器以及Java中內置的安全特性—一起達到一個共同的目的:保持Java虛擬機的實例和它正在運行的應用程序的內部完整性,使得他們不被下載的惡意或有漏洞的代碼侵犯。第四個組成部分是安全管理器,它主要用於保護虛擬機的外部資源不被虛擬機內運行的惡意或有漏洞的代碼侵犯。
• 類裝載器必須將每一個被裝載的類放置在一個保護域中,一個保護域定義了這個代碼在運行時將得到怎樣的權限。