認識Java虛擬機器中的類載入子系統和執行引擎
目錄
一. JVM整體架構
JVM(Java虛擬機器)是一套以軟體方式模擬具有完整硬體系統功能,執行在一個完全隔離環境中的完整計算機系統,是物理機的軟體實現。
1. 目前主流的JVM有以下幾類
- Sun HotSpot VM(2010年被Oracle收購)
- BEA JRockit VM(2008年被Oracle收購)
- IBM J9 VM
- Azul VM
- Apache Harmony
- Google Dalvik VM
- Microsoft JVM
2. JVM由三個主要子系統組成
- 類載入子系統(Class Loader)
- 執行時資料區(Runtime Data Area)
- 執行引擎(Execution Engine)
二. JVM類裝載子系統
(一)類載入過程
類載入:類載入器查詢class檔案並載入到虛擬機器記憶體,並對資料進行校驗、轉換解析和初始化,最終形成可以被虛擬機器直接使用的Java型別資料的過程。
1. 載入:從硬碟查詢並通過IO讀入位元組碼檔案
2. 連結:執行驗證、準備、解析步驟
- 驗證:校驗位元組碼檔案的正確性
- 準備:給類的靜態變數分配記憶體空間,並賦予預設值:Integer=0、string=NULL、Boolean=false...
- 解析:類載入器載入類所引入的其他所有類
3. 初始化:對類中靜態變數初始化為指定的值,並執行靜態程式碼塊
(二)類載入器
-
啟動類載入器(Bootstrap ClassLoader):使用C++實現(僅限於HotSpot),是虛擬機器自身的一部分。負責JRE核心類庫${JRE_HOME}/lib目錄下的類包(如rt.jar、charsets.jar等。)載入到虛擬機器中,其無法被Java程式直接引用。
-
擴充套件類載入器(Extention ClassLoader):由ExtClassLoader實現,負責載入JRE擴充套件目錄${JRE_HOME}/lib/ext下的所有類庫,開發者可以直接使用。
-
應用程式類載入器(Application ClassLoader):由APPClassLoader實現。負責載入使用者類路徑classpath下所指定的類庫。
-
使用者自定義類載入器(Custom ClassLoader):負責載入使用者自定義路徑下的類包,很少使用。
參考下方示例
(三)類載入機制
1. 全盤負責委託機制
當一個ClassLoader載入一個類時,除非顯式地使用另一個ClassLoader,否則該類所依賴和引用的類也由這個ClassLoader載入。
2. 雙親委派機制(Parents Delegation Model)
當一個ClassLoader載入目標類時,它首先將載入請求委託給父類載入器(或上級類載入器)嘗試載入,當父類載入器無法完成載入(ClassLoader在自己的搜尋範圍內找不到目標類)時,子類載入器才會嘗試自己去載入目標類。
3. 雙親委派機制的優勢
- 沙箱安全機制:我們自定義的String.class類不會被載入,防止了核心類庫被篡改。
- 避免類的重複載入:當父類載入器載入了目標類後,就沒必要讓子類載入器再重複載入同一個類。
- JVM對類的載入方式是按需載入,也就是在執行期間動態載入,驗證的方式見下方示例,注意在啟動時載入引數:-verbose:class。
三. JVM執行引擎
執行引擎:讀取執行時資料區的Java位元組碼並逐個執行。
(一)時編譯器(JIT編譯器)
Java程式最初是通過直譯器進行解釋執行的,當虛擬機發現某個方法或程式碼塊的執行特別頻繁,就會把這些程式碼認定為“熱點程式碼”(Hot Spot Code)。
為了提高熱點程式碼的執行效率,在執行時,虛擬機器將會把這些程式碼編譯成與本地平臺相關的機器碼,並進行各種層次的優化,完成這個任務的編譯器成為即時編譯器(Just In Time Compiler,JIT編譯器)。
(二)直譯器和編譯器
許多主流的商用虛擬機器,都同時包含直譯器和編譯器。
- 當程式需要快速啟動和執行時,直譯器首先發揮作用,省去編譯的時間,立即執行。
- 當程式執行後,隨著時間的推移,編譯器逐漸發揮作用,把越來越多的程式碼編譯成原生代碼,可以提高執行效率。
如果記憶體資源限制較大(部分嵌入式系統),可以使用解釋執行節約記憶體,反之可以使用編譯執行來提升效率。同時編譯器的程式碼還能退回成直譯器的程式碼。