關於JVM與GraalVM,此篇稍微紀錄一下GraalVM研讀。不過在理解GraalVM之前須先理解何謂JVM。了解JVM才有辦法理解GraalVM與他的差異之處。
我們要在機台上跑Java Code,一般都需要安裝設置JVM。JVM是一個虛擬機器,它讓Java程式能夠在不同的操作系統和硬體架構上執行。Java以「一次編寫,隨處執行」為理念,這是因為JVM將Java的bytecode翻譯為機器的指令。JVM不僅能運行Java,還支援許多語言如Kotlin、Scala、Groovy等。
要讓Java程式在任何設備上執行,流程如下:
.java → javac → .class(bytecode) → JVM → 機器碼 → 執行
這個流程代表從程式碼經過編譯產生bytecode,JVM會將這些bytecode翻譯成機器能夠理解的指令來執行。JVM的核心功能即是透過Interpretation或JIT Compilation來完成這個任務。
基本上對於Java開發者,較鮮少往JVM的架構去研讀,一般都是JRE安裝好後,確定Java Code能運行就止住了。但要深入了解GraalVM,建議對於JVM是需要一定的認知的。但這區塊會比較偏向編譯器和運行時系統的底層實現,基本上只要過一下大概即可。
會focus在最底層的編譯部分(Execution Engine),後面會對這一塊多加解釋
下圖為JVM的架構概念圖,
基本上分三個區塊
Class Loader(類別加載器)
類別加載器負責將磁碟上的 .class
檔案(即編譯好的bytecode)載入JVM的記憶體中。這個過程包括了:
類別檢驗(Class Verification):類別檢驗是類別加載流程的第一步,用來保證載入的 .class
檔案是正確且不會破壞JVM的安全性或穩定性。JVM透過這個過程來確認:
.class
檔案是否符合Java Class File的結構規範,例如是否有正確的標頭(magic number)、版本號是否支援、是否包含正確的常量池和正確的欄位/方法資訊。這個步驟的主要目的是保證bytecode在執行時不會違反Java語言的規範和JVM的執行規則,從而確保Java應用的安全性和穩定性。
類別解析(Class Resolution)
類別解析的主要任務是將.class
檔案中使用的符號引用(Symbolic Reference)轉換為JVM的直接引用(Direct Reference)。符號引用是指在編譯階段,用文字描述的引用關係,例如某個變數或方法的名稱。直接引用則是指記憶體中的真實位置,這樣JVM可以快速存取變數或方法。
這個步驟包括以下內容:
類別初始化(Class Initialization)
類別初始化是類別加載的最後一個步驟,這個步驟負責執行類別的靜態程式碼和初始化靜態變數。它的主要任務包括:
static int a = 5;
,那麼在初始化時,JVM會為這個變數分配記憶體並賦值為5。static { ... }
),這些程式碼會在初始化階段被執行,通常用來進行類別層級的初始化操作。例如,可能會初始化某些靜態資源或執行一些一次性的設置操作。JVM 記憶體區域
JVM內部分成幾個重要的記憶體區域,分別用於不同的目的:主要職責:存放 JVM 運行時所需的資料,例如類別的資訊、物件、執行緒棧等
執行與原生互動層
是JVM的核心部分,負責實際執行Java的bytecode並處理JVM與本地系統之間的互動。
Execution Engine(執行引擎):
執行JVM內的bytecode。它可以直接解釋執行bytecode,或通過即時編譯器(JIT Compiler)將bytecode轉換為機器碼後執行。執行引擎的設計目的是優化Java程式的運行效能。
Native Method Interface(原生方法介面):
JVM透過JNI與本地程式碼進行互動,使得Java程式可以呼叫非Java程式語言撰寫的函式,例如C或C++撰寫的本地函式。
Native Method Libraries(原生方法函式庫)
這些函式庫包含使用非Java語言(如C或C++)實作的函式,Java程式可以透過JNI呼叫這些函式來與本地系統互動。
上述JVM解析內容 可以被視為一個框架實作參考,它是一套標準的執行環境,用來運行 Java 和其他 JVM 兼容語言的程式。開發者可以專注在編寫和運行程式,不用關心底層的硬體和作業系統。而這個框架本身並不依賴於特定的硬體或作業系統,是通過實現虛擬化層來抽象底層的細節,使得應用程式能夠跨平台運行。
實作 JVM 的方式有很多,不同的 JVM 實作可能會針對特定需求進行優化。常見的 JVM 實作包括:
不同的實作方式允許開發者根據應用場景的需求,選擇最適合的 JVM 版本來獲得最佳性能。