每一個Java開發人員都知道字節碼經由JRE(Java運行時環境)執行。但他們或許不知道JRE實際上是由Java虛擬機(JVM)實現,JVM分析字節碼,解釋並執行它。做爲開發人員,瞭解JVM的架構是很是重要的,由於它使咱們可以編寫出更高效的代碼。本文中,咱們將深刻了解Java中的JVM架構和JVM的各個組件。算法
虛擬機是物理機的軟件實現。Java的設計理念是WORA(Write Once Run Anywhere,一次編寫隨處運行)。編譯器將Java文件編譯爲Java .class文件,而後將.class文件輸入到JVM中,JVM執行類文件的加載和執行的操做。請看如下的JVM架構圖:數組
如上面架構圖所示,JVM分爲三個主要子系統:安全
Java的動態類加載功能由類加載器子系統處理,處理過程包括加載和連接,並在類文件運行時,首次引用類時就開始實例化類文件,而不是在編譯時進行。架構
1.1 加載框架
Boot Strap類加載器,Extension類加載器和Application(類加載器是實現類加載過程的三個類加載器。性能
(1) Boot Strap類加載器:負責從引導類路徑加載類,除了rt.jar,它具備最高優先級;優化
(2) Extension 類加載器:負責加載ext文件夾(jre \ lib)中的類;spa
(3) Application類加載器:負責加載應用程序級類路徑,環境變量中指定的路徑等信息。.net
上面的類裝載器在加載類文件時遵循委託層次算法(Delegation Hierarchy Algorithm)。線程
1.2 連接
(1) 驗證(Verify):字節碼驗證器將驗證生成的字節碼是否正確,若是驗證失敗,將提示驗證錯誤;
(2) 準備(Prepare):對於全部靜態變量,內存將會以默認值進行分配;
(3) 解釋(Resolve):有符號存儲器引用都將替換爲來自方法區(Method Area)的原始引用。
1.3 初始化
這是類加載的最後階段,全部的靜態變量都將被賦予原始值,而且靜態區塊將被執行。
運行時數據區可分爲5個主要組件:
(1) 方法區(Method Area):全部的類級數據將存儲在這裏,包括靜態變量。每一個JVM只有一個方法區,它是一個共享資源;
(2) 堆區域(Heap Area):全部對象及其對應的實例變量和數組將存儲在這裏。每一個JVM也只有一個堆區域。因爲方法和堆區域共享多個線程的內存,所存儲的數據不是線程安全的;
(3) 堆棧區(Stack Area):對於每一個線程,將建立單獨的運行時堆棧。對於每一個方法調用,將在堆棧存儲器中產生一個條目,稱爲堆棧幀。全部局部變量將在堆棧內存中建立。堆棧區域是線程安全的,由於它不共享資源。堆棧框架分爲三個子元素:
(4) PC寄存器(PC Registers):每一個線程都有單獨的PC寄存器,用於保存當前執行指令的地址。一旦執行指令,PC寄存器將被下一條指令更新;
(5) 本地方法堆棧(Native Method stacks):本地方法堆棧保存本地方法信息。對於每一個線程,將建立一個單獨的本地方法堆棧。
分配給運行時數據區的字節碼將由執行引擎執行,執行引擎讀取字節碼並逐個執行。
(1) 解釋器:解釋器更快地解釋字節碼,但執行緩慢。解釋器的缺點是當一個方法被調用屢次時,每次都須要一個新的解釋;
(2) JIT編譯器:JIT編譯器消除了解釋器的缺點。執行引擎將在轉換字節碼時使用解釋器的幫助,可是當它發現重複的代碼時,將使用JIT編譯器,它編譯整個字節碼並將其更改成本地代碼。這個本地代碼將直接用於重複的方法調用,這提升了系統的性能。JIT的構成組件爲:
(3) 垃圾收集器(Garbage Collector):收集和刪除未引用的對象。能夠經過調用「System.gc()」觸發垃圾收集,但不能保證執行。JVM的垃圾回收對象是已建立的對象。
Java本機接口(JNI):JNI將與本機方法庫進行交互,並提供執行引擎所需的本機庫。
本地方法庫(Native Method Libraries):它是執行引擎所需的本機庫的集合。