資訊中心管理
解密 JVM 深入探索 Java 虛擬機 運作原理與最佳實踐
前往目錄
Java 不僅僅是一種程式語言,更是一個「大傘」,涵蓋了工具、執行環境,甚至是一個完整的社群。在本文中,我們想要探討JVM 到底是什麼?

Java 不僅僅是一種程式語言,更是一個「大傘」,涵蓋了工具、執行環境,甚至是一個完整的社群。在本文中,我們想要探討這個傘下的一部分: Java 虛擬機(JVM)。JVM 到底是什麼?以及它是如何運作的? Simon Ritter,Deputy CTO, Azul :「Java 在最受歡迎的程式語言排行榜上一直名列前茅。真正的原因不是語言本身,而是 JVM以及它為開發者提供的強大能力。

JDK、JRE 和 JVM 之間差別是什麼?

軟體產業有許多的術語以及縮寫,為了避免困惑,導致對特定術語的誤用,我們首先需要理解以下術語縮寫的差異。

JDK vs JRE vs JVM

eis109 9 1

JDK:Java 開發工具包(Java Development Kit)

JDK 位於 Java 生態系統的最高層,是所有其他組件的「來源」。每個新的 Java版本都是 JDK 的新版本,其中包含改進、錯誤修正、安全修補以及新增或移除的工具。 JDK 包含數個組件:

● JVM(Java 虛擬機器):這是執行您的應用程式的可執行 Java 程式。它是 Java 語言的核心,負責解釋並執行 Java 應用程式的字節碼。JVM 提供了管理、垃圾回收、執行線程和其他運行時環境的支援

● 開發 Java 應用程式所使用的函式庫是一組包含 5000 多個類別的集合,例如 java.util、java.text、java.nio、java.sql 等。

● 一套工具可協助您建立、監控和執行Java 應用程式,例如:

   • javac:用於將您的 Java 類別編譯為 Bytecode
   • javadoc:從 Java 原始碼文件生成API 文件的 HTML 頁面
   • jshell:在 Shell 終端中與執行 Java程式碼互動並執行它
   • 還有許多其他工具……

JRE:Java 執行環境(Java Runtime Environment)

在 Java 9 之前,每個 JDK 都有相應的JRE,它包含相同的 JVM 和函式庫,但僅提供有限的工具集。因此,它是 JDK的一個子集。

JRE 的目標是在不需要所有工具的設備上執行應用程式,以減少開銷,並提供更小的下載和分發文件。然而,從 Java 9 開始,引入了模組(modules)的概念,使得您可以使用 jlink 建立只包含運行應用程式所需模組的執行環境,從而相對於JDK 和 JRE 而言,創建更小的執行時環境。

由於許多組織仍然依賴並使用 JRE,Azul和其他提供者仍然針對新版本創建 JRE。

JVM 內部的運作過程

正如我們所學到的, Java 虛擬機(JVM)是 JDK 的一部分,它運行我們的應用程式,並被稱為「受管理的執行時環境」。這個術語中的「受管理的」非常重要,因為表示它不僅執行程式碼,還處理了許多額外的功能。JVM 充當您的應用程式與運行的機器之間的中介層。

Java 的承諾:「一次編寫 ,到處執行」

作為開發人員,您只需要編寫一個代碼庫,就可以在任何平台上執行您的程式,包括操作系統( 如 Windows、Mac、Linux 等 ) 和 硬 體( 如 x86、ARM、aarch64 等)。為了實現這一點,您的 Java 代碼需要轉換為 Bytecode。這是您作為開發人員的角色,可以通過像 Maven 或 Gradle 這樣的建構工具使用 javac 來完成。JVM 在機器上執行這些 Bytecode 這意味著任何類別都可以在任何平台上運行!

為了實現這一點,JVM Bytecode 必須對每個支援的操作系統和平台進行「翻譯」,轉換成適用該環境的特定本機碼(native code)。這意味著作為開發人員,您不需要自己為支援不同平台而撰寫不同的程式碼,因為這些工作已經由 Java 系統的開發人員處理。您可以查看原始程式碼,了解在 Java 項目中是如何完成這些工作的,所有這些代碼在 GitHub 上都是免費可用的。連結上,您可以在以下項目的一些截圖中找到HotSpot 虛擬機的不同實現方式。

eis109 9 2

eis109 9 3

即時編譯(Just-In-Time compilation)

當您的應用程式啟動時, Bytecode 會使用JVM 中的範本模型直接轉換為平台指令。此時,還沒有進行任何優化,因此 Java運行速度比類似的本機編譯程式碼要慢。但與此同時, JVM 立即追蹤每個方法被調用的頻率。一旦達到預定的閾值(也稱為HotSpot), JVM 內部的即時編譯器(JIT編譯器)開始進行兩個階段的工作:

● C1 JIT:將程式碼第一次轉換為本機碼

• 一旦檢測到某個方法作為Hotspot,該程式碼將重新編譯為本機碼
• 這個過程盡可能地快速進行,最小化優化,並且在使用此本機碼時,JVM 再次進行分析,以了解它的使用方式

● C2 JIT:達到最佳的優化

• 當再次達到一定閾值時, JVM 將對程式碼進行新的重新編譯為本機碼,但需要更多時間來達到最大效能,並根據分析結果調整以達到最佳性能
• 這表示,生成的本機碼完全符合程式碼的實際最佳運行方式
• 這意味著相同的程式碼可能會因運行環境、需要處理的資料、觸發程式碼執行的事件等因素而產生不同的本機碼
Azul Zulu Prime 包含了 C2 的替代方案:Falcon JIT,它基於開源項目LLVM,在大多數情況下,與傳統的C2 相比,可以產生更高效的程式碼。有關更多資訊,請參閱 Azul 文件中的「使用 Falcon 編譯器」

觀察下方圖表,我們可以看到當從黃色的 Bytecode 轉換為第一次最佳化的程式碼(C1,綠色)時,應用程式的速度如何改善,最終在完成最佳化程式碼(C2,藍色)下達到最佳性能。有關這個主題的更多資訊以及如何「調整」應用程式以改善這些不同步驟的方法,請參閱「分析和調整程式預熱」。

eis109 9 4

JIT(即時編譯)是與 AOT(事先編譯)相對的概念 ,通常在生成的本機碼針對其確切需求進行優化時表現更好。

記憶體管理

JVM 的另一個責任是自動化的記憶體管理。在其他程式語言如 C、C++ 中,作為開發人員,您需要分配(malloc)和釋放記憶體,如果不正確處理,可能會產生記憶體問題。垃圾收集器(GC)是 JVM中負責處理這一部分的組件。它完全解放了您作為開發人員對於管理記憶體使用的擔憂。GC 定期查找不再需要並且在程式碼中未被引用的物件,釋放空間以供重新使用。

eis109 9 5

線程管理

管理線程和線程之間的交互也是由 JVM處理的一個主題。OpenJDK 19 中包含了項目 Loom 和虛擬線程的首個評估版本,介紹了 Java 內部的多層級線程,與操作系統線程無關。這將為 Java 中的線程使用方式創造新的動態。與操作系統線程的數量無關使得效率更高,並且對可擴展性、流式處理或消息應用程序將產生重大影響。

靜態與動態

另一個常聽到的與 Java 相關的術語是它是一種「靜態型語言」。這裡的「靜態」指的是變數的使用方式。當你宣告一個新的值時 ,你需要定義一個型別,並且不能在之後改變它。例如,String label ="Hello, World!" 將不允許你之後將一個數字指派給 label 變數。這點和 JavaScript 等語言不同。對於從動態型別語言轉換到Java 的新手來說,這可能會令人困惑,但這有助於在程式碼執行時避免許多問題和錯誤。

請記住,「靜態」這個詞彙與值的定義方式相關聯,因為相反地,類別在執行時以「動態」方式載入!這使得應用程式可以根據環境或特定設定正確地運作。例如,根據環境設定,在測試時與在正式環境中可以使用不同的資料庫。在每個情況下,其他類別可以動態載入以與資料庫互動。

Azul Builds of OpenJDK」是什麼意思?

所有的 Java 運行時都必須以相同的方式運作,這樣作為使用者,您可以確保您的應用程式無論使用哪個 JDK,都會產生相同的結果。為了實現這一點,每個發行版都必須符合由相關的 Java 規範請求(JSR)通過 Java 社群流程(JCP)定義的 Java SE 規範。

為了驗證這一點,發行版必須通過 Java 技術相容性套件(TCK)的所有測試。這並不意味著所有的發行版都是以相同的方式實現的,儘管大多數都基於OpenJDK ! Azul 提供了兩個符合 TCK的發行版,但它們在很多方面都有很大的差異。

eis109 9 6

eis109 9 7

Java 技術

使用 Azul Platform Prime 可讓下述技術或服務時,降低基礎設施成本並提升效能。

eis109 9 8

總結

JVM(Java 虛擬機)幫助開發人員處理了許多與其他語言相比不需要自己擔心的任務。這讓開發人員能夠更專注於業務邏輯和具體的實作工作。JVM 負責執行 Java程式碼、自動管理,處理線程管理,並提供跨平台的環境。透過將這些任務交給 JVM,開發人員可以專注於撰寫解決特定問題並滿足業務需求的程式碼。簡單來說, JVM 就像是一位幫助開發人員處理瑣碎事務的助手,讓開發人員能夠更有效率地進行開發工作。

eis109 9 9