Java虛擬機體內部繫結構包括class文件、類裝載子系統、運行時數據區、執行引擎、本地方法調用結構,其中運行時數據區包括方法區、堆、Java棧、程序計數器、本地方法棧等。具體結構以下圖所示(摘自Inside Java Virtual Machine): 算法
1. class文件多線程
在Java中,全部源文件都編譯成二進制的字節碼,而後由虛擬機裝載運行。通常這樣的字節碼是以class文件的形式存在。在運行時,由ClassLoader類(System ClassLoader or User-defined ClassLoader)找到對應的class文件,讀取其中的字節碼,而後交由虛擬機解析運行。ide
在class文件中,包含了定義一個類或接口的全部信息,包括類名、訪問權限、父類名、繼承的全部接口、全部字段、全部方法、方法中的代碼、屬性等信息,而且每一個class文件的開頭還包含了魔術值和版本信息,魔術值用以標識當前的字節碼是合法的字節碼,版本表示生成當前字節碼的編譯器版本,從而虛擬機獲知其版本而作特定處理,若是對於虛擬機不支持的字節碼版本號拒絕加載。spa
在class文件中,不少信息都是以字符串的形式存放,好比對外部類成員或方法的引用,這些字符串信息在連接的時候由虛擬機解析。每一個Java類,無論是包成員類仍是內部類都會生成一個單獨的class文件,於是class文件是相對獨立的。詳細信息參考class文件格式。線程
2. 類裝載子系統設計
類裝載子系統負責查找class文件,讀取字節碼,作部分簡單的檢驗,如魔數是否正確,版本是否受支持,各類數據格式是否正確等。部分解析後的字節碼數據存放到方法區中,最後建立字節碼錶明的類或接口的Class實例。指針
在Java中,類裝載系統是經過ClassLoader來完成的。虛擬機規範中,定義了啓動類裝載器和用於定義類裝載器。在sun提供的虛擬機中,包括了啓動類裝載器、擴展類裝載器、系統類裝載器、用戶定義類裝載器。他們以父子鏈的方式組織在一塊兒。除了啓動類裝載器,其餘的裝載器都是ClassLoader的子類。ClassLoader定義了一些方法能夠幫助用戶定義本身的類裝載器,如defineClass等。詳情參考Java中的ClassLoader。調試
如何卸載類數據?(第七章)orm
3. 運行時數據區對象
運行時數據區保存了全部在運行時的信息。包括方法區、Java棧、堆、程序寄存器、本地方法棧等。其中方法區和堆只在虛擬機中保存一份實例,於是須要處理多線程的同步問題;Java棧、程序寄存器是每一個線程中有單獨的實例,於是對不一樣的線程,他們的數據是私有的。
3.1 方法區
方法區中保存了讀取的字節碼信息(包括常量池,靜態方法和靜態成員信息)、字節碼錶明的Class類實例、一個指向加載它的ClassLoader實例。
Java程序能夠有兩種方式來獲取某個類的Class實例:
1. Class.forName()方法
2. Object.getClass()方法
經過Class實例獲取和該類或接口相關的任何信息。參考Class類的定義。
(注:對有啓動ClassLoader加載的類,Class方法中的getClassLoader方法返回null)
爲加快執行速度,能夠在方法區中引入方法表機制,記錄能被外界調用的該類的實例方法,包括父類中繼承下來的方法。(第八章詳細介紹?)
方法區中根據類名搜索類信息,算法:散列、搜索樹等。
3.2 Java棧
虛擬機爲每一個線程生成一個Java棧,於是對不一樣的線程,棧內的數據都是私有的。Java棧由棧幀組成,Java棧的操做只有兩種,壓入棧幀和彈出棧幀。線程中每一個方法的調用都會在Java棧壓入一個棧幀;每次方法返回(正常方法或拋異常返回),該方法對應的棧幀都會從棧中彈出。
3.2.1 棧幀
棧幀由操做數棧、局部變量區和棧幀數據組成。因爲Java中的指令是基於棧而設計的,於是不少指令的默認操做數就是操做數棧中的數據。操做數棧用於保存指令的操做數和指令操做後的結果。
局部變量區用於保存當前方法的局部變量。
棧幀數據區則保存當前棧幀的信息,如指向當前類常量池的指針,用於操做數爲常量池索引的指令;還有一些和特定虛擬機實現相關的信息和調試信息。
3.3 程序寄存器
每一個線程在執行時都會保存當前指令的下一條指令的地址,以控制程序的之行流程。
3.4 堆
堆保存了程序在運行時的全部對象。在Java中,全部的對象都是保存在堆中的,而外部經過對象的引用來訪問對象。因爲Java存在垃圾回收器,於是Java對象可能被移動,以減小內存碎片。其中一種實現能夠很好的解決移動對象而須要改變全部該對象的引用變量的技術,即將堆分爲句柄池和對象池。對象池中的對象保存了對象的真正內容,而句柄池中的項包含兩個指針,一個指向對象,一個指向類數據。一個對象引用就是指向句柄的對象指針。這樣當須要移動對象時,對象的地址更改之後,就不須要將每一個引用的值都進行更改,只要改變句柄池中指向對象的指針值便可。然而這種設計是以犧牲速度爲代價的,由於這樣每次訪問對象就要多經歷一次指針定位。
在某些垃圾回收器實現中,對象須要額外的信息,若是引用計數的垃圾收集器,須要爲每一個對象記錄引用計數信息;而對另外有些機制,則可能須要暫時保存某些數據。這些額外的數據能夠保存在類中,也能夠在記錄在其餘地方。相似的還有同步機制中的數據和記錄是否已經調用過finalize方法的信息。
在Java中有指令用於在內存中分配對象,卻沒有顯式的指令來釋放內存中的對象。
3.5 本地方法棧
當Java方法調用本地方法的時候,當前線程的程序寄存器是不肯定的值。程序的執行也轉向本地方法。本地方法能夠正常返回,也能夠拋出異常。拋出的異常會在調用該本地方法的指令中從新拋出。
4. 執行引擎
每一個用戶線程(即不包括垃圾回收線程等)都有一個執行引擎實例,用以執行字節碼指令。
5. 本地方法接口
Java程序能夠經過本地方法接口來調用本地方法。