詳細介紹什麼是Java虛擬機

1、什麼是Java虛擬機
     當你談到Java虛擬機時,你多是指:
     一、抽象的Java虛擬機規範
     二、一個具體的Java虛擬機實現
     三、一個運行的Java虛擬機實例
2、Java虛擬機的生命週期
     一個運行中的Java虛擬機有着一個清晰的任務:執行Java程序。程序開始執行時他才運行,程序結束時他就中止。你在同一臺機器上運行三個程序,就會有三個運行中的Java虛擬機。
     Java虛擬機老是開始於一個main()方法,這個方法必須是公有、返回void、直接受一個字符串數組。在程序執行時,你必須給Java虛擬機指明這個包換main()方法的類名。
     Main()方法是程序的起點,他被執行的線程初始化爲程序的初始線程。程序中其餘的線程都由他來啓動。Java中的線程分爲兩種:守護線程 (daemon)和普通線程(non-daemon)。守護線程是Java虛擬機本身使用的線程,好比負責垃圾收集的線程就是一個守護線程。固然,你也可 以把本身的程序設置爲守護線程。包含Main()方法的初始線程不是守護線程。
     只要Java虛擬機中還有普通的線程在執行,Java虛擬機就不會中止。若是有足夠的權限,你能夠調用exit()方法終止程序。
3、Java虛擬機的體系結構
     在Java虛擬機的規範中定義了一系列的子系統、內存區域、數據類型和使用指南。這些組件構成了Java虛擬機的內部結構,他們不只僅爲Java虛擬機的實現提供了清晰的內部結構,更是嚴格規定了Java虛擬機實現的外部行爲。 
     每個Java虛擬機都由一個類加載器子系統(class loader subsystem),負責加載程序中的類型(類和接口),並賦予惟一的名字。每個Java虛擬機都有一個執行引擎(execution engine)負責執行被加載類中包含的指令。
     程序的執行須要必定的內存空間,如字節碼、被加載類的其餘額外信息、程序中的對象、方法的參數、返回值、本地變量、處理的中間變量等等。Java虛擬機將 這些信息通通保存在數據區(data areas)中。雖然每一個Java虛擬機的實現中都包含數據區,可是Java虛擬機規範對數據區的規定卻很是的抽象。許多結構上的細節部分都留給了 Java虛擬機實現者本身發揮。不一樣Java虛擬機實現上的內存結構千差萬別。一部分實現可能佔用不少內存,而其餘如下可能只佔用不多的內存;一些實現可 能會使用虛擬內存,而其餘的則不使用。這種比較精煉的Java虛擬機內存規約,可使得Java虛擬機能夠在普遍的平臺上被實現。
     數據區中的一部分是整個程序共有,其餘部分被單獨的線程控制。每個Java虛擬機都包含方法區(method area)和堆(heap),他們都被整個程序共享。Java虛擬機加載並解析一個類之後,將從類文件中解析出來的信息保存與方法區中。程序執行時建立的 對象都保存在堆中。 
     當一個線程被建立時,會被分配只屬於他本身的PC寄存器「pc register」(程序計數器)和Java堆棧(Java stack)。當線程不掉用本地方法時,PC寄存器中保存線程執行的下一條指令。Java堆棧保存了一個線程調用方法時的狀態,包括本地變量、調用方法的 參數、返回值、處理的中間變量。調用本地方法時的狀態保存在本地方法堆棧中(native method stacks),可能再寄存器或者其餘非平臺獨立的內存中。
     Java堆棧有堆棧塊(stack frames (or frames))組成。堆棧塊包含Java方法調用的狀態。當一個線程調用一個方法時,Java虛擬機會將一個新的塊壓到Java堆棧中,當這個方法運行結束時,Java虛擬機會將對應的塊彈出並拋棄。
     Java虛擬機不使用寄存器保存計算的中間結果,而是用Java堆棧在存放中間結果。這是的Java虛擬機的指令更緊湊,也更容易在一個沒有寄存器的設備上實現Java虛擬機。 
     圖中的Java堆棧中向下增加的,PC寄存器中線程三爲灰色,是由於它正在執行本地方法,他的下一條執行指令不保存在PC寄存器中。
4、數據類型(Data Types)
     全部Java虛擬機中使用的數據都有肯定的數據類型,數據類型和操做都在Java虛擬機規範中嚴格定義。Java中的數據類型分爲原始數據類型 (primitive types)和引用數據類型(reference type)。引用類型依賴於實際的對象,但不是對象自己。原始數據類型不依賴於任何東西,他們就是自己表示的數據。
全部Java程序語言中的原始 數據類型,都是Java虛擬機的原始數據類型,除了布爾型(boolean)。當編譯器將Java源代碼編譯爲本身碼時,使用整型(int)或者字節型 (byte)去表示布爾型。在Java虛擬機中使用整數0表示布爾型的false,使用非零整數表示布爾型的true,布爾數組被表示爲字節數組,雖然他 們可能會以字節數組或者字節塊(bit fields)保存在堆中。
     除了布爾型,其餘Java語言中的原始類型都是Java虛擬機中的數據類型。在Java中數據類型被分爲:整形的byte,short,int,long;char和浮點型的float,double。Java語言中的數據類型在任何主機上都有一樣的範圍。 
     在Java虛擬機中還存在一個Java語言中不能使用的原始數據類型返回值類型(returnValue)。這種類型被用來實現Java程序中的「finally clauses」,具體的參見18章的「Finally Clauses」。
     引用類型可能被建立爲:類類型(class type),接口類型(interface type),數組類型(array type)。他們都引用被動態建立的對象。當引用類型引用null時,說明沒有引用任何對象。
     Java虛擬機規範只定義了每一種數據類型表示的範圍,沒有定義在存儲時每種類型佔用的空間。他們如何存儲由Java虛擬機的實現者本身決定。關於浮點型更多信息參見14章「Floating Point Arithmetic」。java

TypeRange
byte8-bit signed two's complement integer (-27 to 27 - 1, inclusive)
short16-bit signed two's complement integer (-215 to 215 - 1, inclusive)
int32-bit signed two's complement integer (-231 to 231 - 1, inclusive)
long64-bit signed two's complement integer (-263 to 263 - 1, inclusive)
char16-bit unsigned Unicode character (0 to 216 - 1, inclusive)
float32-bit IEEE 754 single-precision float
double64-bit IEEE 754 double-precision float
returnValueaddress of an opcode within the same method
referencereference to an object on the heap, or null
5、字節長度
     Java虛擬機中最小的數據單元式字(word),其大小由Java虛擬機的實現者定義。可是一個字的大小必須足夠容納byte,short,int, char,float,returnValue,reference;兩個字必須足夠容納long,double。因此虛擬機的實現者至少提供的字不能小 於31bits的字,可是最好選擇特定平臺上最有效率的字長。
     在運行時,Java程序不能決定所運行機器的字長。字長也不會影響程序的行爲,他只是在Java虛擬機中的一種表現方式。
6、類加載器子系統
     Java虛擬機中的類加載器分爲兩種:原始類加載器(primordial class loader)和類加載器對象(class loader objects)。原始類加載器是Java虛擬機實現的一部分,類加載器對象是運行中的程序的一部分。不一樣類加載器加載的類被不一樣的命名空間所分割。
     類加載器調用了許多Java虛擬機中其餘的部分和java.lang包中的不少類。好比,類加載對象就是java.lang.ClassLoader子類 的實例,ClassLoader類中的方法能夠訪問虛擬機中的類加載機制;每個被Java虛擬機加載的類都會被表示爲一個 java.lang.Class類的實例。像其餘對象同樣,類加載器對象和Class對象都保存在堆中,被加載的信息被保存在方法區中。
     一、加載、鏈接、初始化(Loading, Linking and Initialization)
類加載子系統不只僅負責定位並加載類文件,他按照如下嚴格的步驟做了不少其餘的事情:(具體的信息參見第七章的「類的生命週期」)
          1)、加載:尋找並導入指定類型(類和接口)的二進制信息
          2)、鏈接:進行驗證、準備和解析
               ①驗證:確保導入類型的正確性
               ②準備:爲類型分配內存並初始化爲默認值
               ③解析:將字符引用解析爲直接飲用
          3)、初始化:調用Java代碼,初始化類變量爲合適的值
     二、原始類加載器(The Primordial Class Loader)
     每一個Java虛擬機都必須實現一個原始類加載器,他可以加載那些遵照類文件格式而且被信任的類。可是,Java虛擬機的規範並無定義如何加載類,這由 Java虛擬機實現者本身決定。對於給定類型名的類型,原始萊加載器必須找到那個類型名加「.class」的文件並加載入虛擬機中。
     三、類加載器對象
     雖然類加載器對象是Java程序的一部分,可是ClassLoader類中的三個方法能夠訪問Java虛擬機中的類加載子系統。
          1)、protected final Class defineClass(…):使用這個方法能夠出入一個字節數組,定義一個新的類型。
          2)、protected Class findSystemClass(String name):加載指定的類,若是已經加載,就直接返回。
          3)、protected final void resolveClass(Class c):defineClass()方法只是加載一個類,這個方法負責後續的動態鏈接和初始化。
     具體的信息,參見第八章「鏈接模型」( The Linking Model)。
     四、命名空間
     當多個類加載器加載了同一個類時,爲了保證他們名字的惟一性,須要在類名前加上加載該類的類加載器的標識。具體的信息,參見第八章「鏈接模型」( The Linking Model)。
7、方法區(The Method Area)
     在Java虛擬機中,被加載類型的信息都保存在方法區中。這寫信息在內存中的組織形式由虛擬機的實現者定義,好比,虛擬機工做在一個「little- endian」的處理器上,他就能夠將信息保存爲「little-endian」格式的,雖然在Java類文件中他們是以「big-endian」格式保 存的。設計者能夠用最適合並地機器的表示格式來存儲數據,以保證程序可以以最快的速度執行。可是,在一個只有很小內存的設備上,虛擬機的實現者就不會佔用 很大的內存。
     程序中的全部線程共享一個方法區,因此訪問方法區信息的方法必須是線程 安全的。若是你有兩個線程都去加載一個叫Lava的類,那隻能由一個線程被允許去加載這個類,另外一個必須等待。
     在程序運行時,方法區的大小是可變的,程序在運行時能夠擴展。有些Java虛擬機的實現也能夠經過參數也訂製方法區的初始大小,最小值和最大值。
     方法區也能夠被垃圾收集。由於程序中的內由類加載器動態加載,全部類可能變成沒有被引用(unreferenced)的狀態。當類變成這種狀態時,他就可 能被垃圾收集掉。沒有加載的類包括兩種狀態,一種是真正的沒有加載,另外一個種是「unreferenced」的狀態。詳細信息參見第七章的類的生命週期 (The Lifetime of a Class)。
     一、類型信息(Type Information)
          每個被加載的類型,在Java虛擬機中都會在方法區中保存以下信息:
          1)、類型的全名(The fully qualified name of the type)
          2)、類型的父類型的全名(除非沒有父類型,或者弗雷形式java.lang.Object)(The fully qualified name of the typeís direct superclass)
          3)、給類型是一個類仍是接口(class or an interface)(Whether or not the type is a class )
          4)、類型的修飾符(public,private,protected,static,final,volatile,transient等)(The typeís modifiers)
          5)、全部父接口全名的列表(An ordered list of the fully qualified names of any direct superinterfaces)
          類型全名保存的數據結構由虛擬機實現者定義。除此以外,Java虛擬機還要爲每一個類型保存以下信息:
          1)、類型的常量池(The constant pool for the type)
          2)、類型字段的信息(Field information)
          3)、類型方法的信息(Method information)
          4)、全部的靜態類變量(很是量)信息(All class (static) variables declared in the type, except constants)
          5)、一個指向類加載器的引用(A reference to class ClassLoader)
          6)、一個指向Class類的引用(A reference to class Class)


          1)、類型的常量池(The constant pool for the type)
          常量池中保存中全部類型是用的有序的常量集合,包含直接常量(literals)如字符串、整數、浮點數的常量,和對類型、字段、方法的符號引用。常量池 中每個保存的常量都有一個索引,就像數組中的字段同樣。由於常量池中保存中全部類型使用到的類型、字段、方法的字符引用,因此它也是動態鏈接的主要對 象。詳細信息參見第六章「The Java Class File」。
          2)、類型字段的信息(Field information)
          字段名、字段類型、字段的修飾符(public,private,protected,static,final,volatile,transient等)、字段在類中定義的順序。
          3)、類型方法的信息(Method information)
          方法名、方法的返回值類型(或者是void)、方法參數的個數、類型和他們的順序、字段的修飾符(public,private,protected,static,final,volatile,transient等)、方法在類中定義的順序
          若是不是抽象和本地本法還須要保存
          方法的字節碼、方法的操做數堆棧的大小和本地變量區的大小(稍候有詳細信息)、異常列表(詳細信息參見第十七章「Exceptions」。)
          4)、類(靜態)變量(Class Variables)
          類變量被全部類的實例共享,即便不經過類的實例也能夠訪問。這些變量綁定在類上(而不是類的實例上),因此他們是類的邏輯數據的一部分。在Java虛擬機使用這個類以前就須要爲類變量(non-final)分配內存
          常量(final)的處理方式於這種類變量(non-final)不同。每個類型在用到一個常量的時候,都會複製一份到本身的常量池中。常量也像類變 量同樣保存在方法區中,只不過他保存在常量池中。(多是,類變量被全部實例共享,而常量池是每一個實例獨有的)。Non-final類變量保存爲定義他的 類型數據(data for the type that declares them)的一部分,而final常量保存爲使用他的類型數據(data for any type that uses them)的一部分。詳情參見第六章「The Java Class FileThe Java Class File」
          5)、指向類加載器的引用(A reference to class ClassLoader)
          每個被Java虛擬機加載的類型,虛擬機必須保存這個類型是否由原始類加載器或者類加載器加載。那些被類加載器加載的類型必須保存一個指向類加載器的引 用。當類加載器動態鏈接時,會使用這條信息。當一個類引用另外一個類時,虛擬機必須保存那個被引用的類型是被同一個類加載器加載的,這也是虛擬機維護不一樣命 名空間的過程。詳情參見第八章「The Linking Model」
          6)、指向Class類的引用(A reference to class Class)
          Java虛擬機爲每個加載的類型建立一個java.lang.Class類的實例。你也能夠經過Class類的方法:
public static Class forName(String className)來查找或者加載一個類,並取得相應的Class類的實例。經過這個Class類的實例,咱們能夠訪問Java虛擬機方法區中的信息。具體參照Class類的JavaDoc。
     二、方法列表(Method Tables)
     爲了更有效的訪問全部保存在方法區中的數據,這些數據的存儲結構必須通過仔細的設計。全部方法區中,除了保存了上邊的那些原始信息外,還有一個爲了加快存 取速度而設計的數據結構,好比方法列表。每個被加載的非抽象類,Java虛擬機都會爲他們產生一個方法列表,這個列表中保存了這個類可能調用的全部實例 方法的引用,報錯那些父類中調用的方法。詳情參見第八章「The Linking Model」數組

8、堆
     當Java程序建立一個類的實例或者數組時,都在堆中爲新的對象分配內存。虛擬機中只有一個堆,全部的線程都共享他。
     一、垃圾收集(Garbage Collection)
     垃圾收集是釋放沒有被引用的對象的主要方法。它也可能會爲了減小堆的碎片,而移動對象。在Java虛擬機的規範中沒有嚴格定義垃圾收集,只是定義一個Java虛擬機的實現必須經過某種方式管理本身的堆。詳情參見第九章「Garbage Collection」。
     二、對象存儲結構(Object Representation)
     Java虛擬機的規範中沒有定義對象怎樣在堆中存儲。每個對象主要存儲的是他的類和父類中定義的對象變量。對於給定的對象的引用,虛擬機必須嫩耨很快的 定位到這個對象的數據。另爲,必須提供一種經過對象的引用方法對象數據的方法,好比方法區中的對象的引用,因此一個對象保存的數據中每每含有一個某種形式 指向方法區的指針。
     一個可能的堆的設計是將堆分爲兩個部分:引用池和對象池。一個對象的引用就是指向引用池的本地指針。每個引用池中的條目都包含兩個部分:指向對象池中對 象數據的指針和方法區中對象類數據的指針。這種設計可以方便Java虛擬機堆碎片的整理。當虛擬機在對象池中移動一個對象的時候,只須要修改對應引用池中 的指針地址。可是每次訪問對象的數據都須要處理兩次指針。下圖演示了這種堆的設計。在第九章的「垃圾收集」中的HeapOfFish Applet演示了這種設計。 
     另外一種堆的設計是:一個對象的引用就是一個指向一堆數據和指向相應對象的偏移指針。這種設計方便了對象的訪問,但是對象的移動要變的異常複雜。下圖演示了這種設計 
     當程序試圖將一個對象轉換爲另外一種類型時,虛擬機須要判斷這種轉換是不是這個對象的類型,或者是他的父類型。當程序適用instanceof語句的時候也 會作相似的事情。當程序調用一個對象的方法時,虛擬機須要進行動態綁定,他必須判斷調用哪個類型的方法。這也須要作上面的判斷。
     不管虛擬機實現者使用哪種設計,他均可能爲每個對象保存一個相似方法列表的信息。由於他能夠提高對象方法調用的速度,對提高虛擬機的性能很是重要,但 是虛擬機的規範中比沒有要求必須實現相似的數據結構。下圖描述了這種結構。圖中顯示了一個對象引用相關聯的全部的數據結構,包括:
          1)、一個指向類型數據的指針
          2)、一個對象的方法列表。方法列表是一個指向全部可能被調用對象方法的指針數組。方法數據包括三個部分:操做碼堆棧的大小和方法堆棧的本地變量區;方法的字節碼;異常列表。
          每個Java虛擬機中的對象必須關聯一個用於同步多線程的lock(mutex)。同一時刻,只能有一個對象擁有這個對象的鎖。當一個擁有這個這個對象 的鎖,他就能夠屢次申請這個鎖,可是也必須釋放相應次數的鎖才能真正釋放這個對象鎖。不少對象在整個生命週期中都不會被鎖,因此這個信息只有在須要時才需 要添加。不少Java虛擬機的實現都沒有在對象的數據中包含「鎖定數據」,只是在須要時才生成相應的數據。除了實現對象的鎖定,每個對象還邏輯關聯到一 個「wait set」的實現。鎖定幫組線程獨立處理共享的數據,不須要妨礙其餘的線程。「wait set」幫組線程協做完成同一個目標。「wait set」每每經過Object類的wait()和notify()方法來實現。 
     垃圾收集也須要堆中的對象是否被關聯的信息。Java虛擬機規範中指出垃圾收集一個運行一個對象的finalizer方法一次,可是允許 finalizer方法從新引用這個對象,當這個對象再次不被引用時,就不須要再次調用finalize方法。因此虛擬機也須要保存finalize方法 是否運行過的信息。更多信息參見第九章的「垃圾收集」
     三、數組的保存(Array Representation)
在Java 中,數組是一種徹底意義上的對象,他和對象同樣保存在堆中、有一個指向Class類實例的引用。全部同一維度和類型的數組擁有一樣的Class,數組的長 度不作考慮。對應Class的名字表示爲維度和類型。好比一個整型數據的Class爲「[I」,字節型三維數組Class名爲「[[[B」,兩維對象數據 Class名爲「[[Ljava.lang.Object」。
多維數組被表示爲數組的數組,以下圖: 
     數組必須在堆中保存數組的長度,數組的數據和一些對象數組類型數據的引用。經過一個數組引用的,虛擬機應該可以取得一個數組的長度,經過索引可以訪問特定 的數據,可以調用Object定義的方法。Object是全部數據類的直接父類。更多信息參見第六章「類文件」。
9、PC寄存器(程序計數器)(The Program Counter)
     每個線程開始執行時都會被建立一個程序計數器。程序計數器只有一個字長(word),因此它可以保存一個本地指針和returnValue。當線程執行 時,程序計數器中存放了正在執行指令的地址,這個地址可使一個本地指針,也可使一個從方法字節碼開始的偏移指針。若是執行本地方法,程序計數器的值沒 有被定義。
10、Java堆棧(The Java Stack)
     當一個線程啓動時,Java虛擬機會爲他建立一個Java堆棧。Java堆棧用一些離散的frame類紀錄線程的狀態。Java虛擬機堆Java堆棧的操做只有兩種:壓入和彈出frames。
     線程中正在執行的方法被稱爲當前方法(current method),當前方法所對應的frame被稱爲當前幀(current frame)。定義當前方法的類被稱爲當前類(current class),當前類的常量池被稱爲當前常量池(current constant pool.)。當線程執行時,Java虛擬機會跟蹤當前類和當前常量池。但線程操做保存在幀中的數據時,他只操做當前幀的數據。
     當線程調用一個方法時,虛擬機會生成一個新的幀,並壓入線程的Java堆棧。這個新的幀變成當前幀。當方法執行時,他使用當前幀保存方法的參數、本地變 量、中間結構和其餘數據。方法有兩種退出方式:正常退出和異常推出。不管方法以哪種方式推出,Java虛擬機都會彈出並丟棄方法的幀,上一個方法的幀變 爲當前幀。
     全部保存在幀中的數據都只能被擁有它的線程訪問,線程不能訪問其餘線程的堆棧中的數據。因此,訪問方法的本地變量時,不須要考慮多線程同步。
     和方法區、堆同樣,Java堆棧不須要連續的內存空間,它能夠被保存在一個分散的內存空間或者堆上。堆棧具體的數據和長度都有Java虛擬機的實現者本身定義。一些實現可能提供了執行堆棧最大值和最小值的方法。
11、堆棧幀(The Stack Frame)
     堆棧幀包含三部分:本地變量、操做數堆棧和幀數據。本地變量和操做數堆棧的大小都是一字(word)爲單位的,他們在編譯就已經肯定。幀數據的大小取決於 不一樣的實現。當程序調用一個方法時,虛擬機從類數據中取得本地變量和操做數堆棧的大小,建立一個合適大小和幀,而後壓入Java堆棧中。
     一、本地變量(Local Variables)
     本地變量在Java堆棧幀中被組織爲一個從0計數的數組,指令經過提供他們的索引從本地變量區中取得相應的值。Int,float,reference, returnValue佔一個字,byte,short,char被轉換成int而後存儲,long和doubel佔兩個字。
     指令經過提供兩個字索引中的前一個來取得long,doubel的值。好比一個long的值存儲在索引3,4上,指令就能夠經過3來取得這個long類型的值。
     本地變量區中包含了方法的參數和本地變量。編譯器將方法的參數以他們申明的順序放在數組的前面。可是編譯器卻能夠將本地變量任意排列在本地變量數組中,甚至兩個本地變量能夠公用一個地址,好比,當兩個本地變量在兩個不交疊的區域內,就像循環變量i,j。
     虛擬機的實現者可使用任何結構來描述本地變量區中的數據,虛擬機規範中沒有定義如何存儲long和doubel。
     二、操做數堆棧(Operand Stack)
     向本地變量同樣,操做數堆棧也被組織爲一個以字爲單位的數組。可是不像本地變量那樣經過索引訪問,而是經過push和pop值來實現訪問的。若是一個指令push一個值到堆棧中,那麼下一個指令就能夠pop而且使用這個值。
     操做數堆棧不像程序計數器那樣不能夠被指令直接訪問,指令能夠直接訪問操做數堆棧。Java虛擬機是一個以堆棧爲基礎,而不是以寄存器爲基礎的,由於它的 指令從堆棧中取得操做數,而不是同寄存器中。固然,指令也能夠從其餘地方去的操做數,好比指令後面的操做碼,或者常量池。可是Java虛擬機指令主要是從 操做數堆棧中取得他們須要的操做數。
     Java虛擬機將操做數堆棧視爲工做區,不少指令經過先從操做數堆棧中pop值,在處理完之後再將結果push回操做數堆棧。一個add的指令執行過程如 下圖所示:先執行iload_0和iload_1兩條指令將須要相加的兩個數,從本地方法區中取出,並push到操做數堆棧中;而後執行iadd指令,現 pop出兩個值,相加,並將結果pusp進操做數堆棧中;最後執行istore_2指令,pop出結果,賦值到本地方法區中。 
     三、幀數據(Frame Data)
     處理本地變量和操做數堆棧之外,java堆棧幀還包括了爲了支持常量池,方法返回值和異常分發須要的數據,他們被保存在幀數據中。
     當虛擬機遇到使用指向常量池引用的指令時,就會經過幀數據中指向常量區的指針來訪問所須要的信息。前面提到過,常量區中的引用在最開始時都是符號引用。即便當虛擬機檢查這些引用時,他們也是字符引用。因此虛擬機須要在這時轉換這個引用。
     當一個方法正常返回時,虛擬機須要重建那個調用這個方法的方法的堆棧幀。若是執行完的方法有返回值,虛擬機就須要將這個值push進調用方法的哪一個操做數堆棧中。
     幀數據中也包含虛擬機用來處理異常的異常表的引用。異常表定義了一個被catch語句保護的一段字節碼。每個異常表中的個體又包含了須要保護的字節瑪的 範圍,和異常被捕捉到時須要執行的字節碼的位置。當一個方法拋出一個異常時,Java虛擬機就是用異常表去判斷如何處理這個異常。若是虛擬機找到了一個匹 配的catch,他就會將控制權交給catch語句。若是沒有找到匹配的catch,方法就會異常返回,而後再調用的方法中繼續這個過程。
     除了以上的三個用途外,幀數據還可能包含一些依賴於實現的數據,好比調試的信息。
12、本地方法堆棧
     本地方法區依賴於虛擬機的不一樣實現。虛擬機的實現者能夠本身決定使用哪種機制去執行本地方法。
     任何本地方法接口(Native Method Interface)都使用某種形式的本地方法堆棧。 
十3、執行引擎
     一個java虛擬機實現的核心就是執行引擎。在Java虛擬機規範,執行引擎被描述爲一系列的指令。對於每個指令,規範都描述了他們應該作什麼,可是沒有說要如何去作。
     一、指令集
     在Java虛擬機中一個方法的字節碼流就是一個指令的序列。每個指令由一個字節的操做碼(Opcode)和可能存在的操做數(Operands)。操做 碼指示去作什麼,操做數提供一些執行這個操做碼可能須要的額外的信息。一個抽象的執行引擎每次執行一個指令。這個過程發生在每個執行的線程中。
有時,執行引擎可能會遇到一個須要調用本地方法的指令,在這種狀況下,執行引擎會去試圖調用本地方法,但本地方法返回時,執行引擎會繼續執行字節碼流中的下一個指令。本地方法也能夠當作對Java虛擬機中的指令集的一種擴充。
     決定下一步執行那一條指令也是執行引擎工做的一部分。執行引擎有三種方法去取得下一條指令。多數指令會執行跟在他會面的指令;一些像goto, return的指令,會在他們執行的時候決定他們的下一條指令;當一個指令拋出異常時,執行引擎經過匹配catch語句來決定下一條應該執行的指令。
     平臺獨立性、網絡移動性、安全性左右了Java虛擬機指令集的設計。平臺獨立性是指令集設計的主要影響因素之一。基於堆棧的結構使得Java虛擬機能夠在 更多的平臺上實現。更小的操做碼,緊湊的結構使得字節碼能夠更有效的利用網絡帶寬。一次性的字節碼驗證,使得字節碼更安全,而不影響太多的性能。
     二、執行技術
     許多種執行技術能夠用在Java虛擬機的實現中:解釋執行,及時編譯(just-in-time compiling),hot-spot compiling,native execution in silicon。
     三、線程
     Java虛擬機規範定義了一種爲了在更多平臺上實現的線程模型。Java線程模型的一個目標時能夠利用本地線程。利用本地線程可讓Java程序中的線程能過在多處理器機器上真正的同時執行。
     Java線程模型的一個代價就是線程優先級,一個Java線程能夠在1-10的優先級上運行。1最低,10最高。若是設計者使用了本地線程,他們可能將這 10個優先級映射到本地優先級上。Java虛擬機規範只定義了,高一點優先級的線程能夠卻一些cpu時間,低優先級的線程在全部高優先級線程都堵塞時,也 能夠獲取一些cpu時間,可是這沒有保證:低優先級的線程在高優先級線程沒有堵塞時不能夠得到必定的cpu時間。所以,若是須要在不一樣的線程間協做,你必 須使用的「同步(synchronizatoin)」。
     同步意味着兩個部分:對象鎖(object locking)和線程等待、激活(thread wait and notify)。對象鎖幫助線程能夠不受其餘線程的干擾。線程等待、激活可讓不一樣的線程進行協做。
     在Java虛擬機的規範中,Java線程被描述爲變量、主內存、工做內存。每個Java虛擬機的實例都有一個主內存,他包含了全部程序的變量:對象、數組合類變量。每個線程都有本身的工做內存,他保存了哪些他可能用到的變量的拷貝。規則:
          1)、從主內存拷貝變量的值到工做內存中
          2)、將工做內存中的值寫會主內存中
     若是一個變量沒有被同步化,線程可能以任何順序更新主內存中的變量。爲了保證多線程程序的正確的執行,必須使用同步機制。
十4、本地方法接口(Native Method Interface)
     Java虛擬機的實現並非必須實現本地方法接口。一些實現可能根本不支持本地方法接口。Sun的本地方法接口是JNI(Java Native Interface)。
十5、現實中的機器(The Real Machine)
十6、數學方法:仿真(Eternal Math : A Simulation)
安全

相關文章
相關標籤/搜索