JVM底層原理解析
本文轉(zhuǎn)載自微信公眾號「極客重生」,作者極客重生。轉(zhuǎn)載本文請聯(lián)系極客重生公眾號。
hi ,大家好,我是極客重生的Alex,今天分享一篇JVM底層原理的文章,希望可以幫助大家了解一下語言虛擬機(jī)一些設(shè)計原理,不管你當(dāng)前使用語言是C,C++,Golang,Python等,很多思想和原理是相通的,可以借鑒。
比如之前分析內(nèi)核虛擬機(jī)eBPF架構(gòu):
詳細(xì)請看:Linux網(wǎng)絡(luò)新技術(shù)基石 |eBPF and XDP
在本文中,您將學(xué)習(xí)
- JVM架構(gòu)
- 軟件代碼編譯執(zhí)行流程
- C代碼編譯執(zhí)行過程
- Java代碼編譯執(zhí)行過程
- 為什么Java既是解釋型語言又是編譯型語言?
- 為什么 Java 很慢?
什么是JVM?
Java 虛擬機(jī) (JVM)是提供運(yùn)行時環(huán)境來驅(qū)動 Java 代碼或應(yīng)用程序的引擎。它將 Java 字節(jié)碼轉(zhuǎn)換為機(jī)器語言。JVM 是 Java 運(yùn)行環(huán)境 (JRE) 的一部分。在其他編程語言中,編譯器為特定系統(tǒng)生成機(jī)器代碼。但是,Java編譯器為稱為Java 虛擬機(jī)的虛擬機(jī)生成代碼。
JVM的工作原理
首先,Java 代碼被編譯成字節(jié)碼,這個字節(jié)碼在不同的機(jī)器上被解釋,在主機(jī)系統(tǒng)和 Java 源代碼之間,字節(jié)碼是一種中介語言,Java 中的 JVM 負(fù)責(zé)分配內(nèi)存空間。
Java 虛擬機(jī) (JVM) 的工作
JVM架構(gòu)
讓我們了解 JVM 的架構(gòu)。Java 中的 JVM 架構(gòu)包含類加載器、內(nèi)存區(qū)、執(zhí)行引擎等。
Java 虛擬機(jī)架構(gòu)
1) 類加載器
類加載器是用于加載類文件的子系統(tǒng)。它執(zhí)行三個主要功能,即。加載、鏈接和初始化。
2) 方法區(qū)
JVM 方法區(qū)存儲類結(jié)構(gòu),如元數(shù)據(jù)、常量運(yùn)行時池和方法代碼。
3) 堆
所有的Objects及其相關(guān)的實(shí)例變量和數(shù)組都存儲在堆中。此內(nèi)存是通用的,并在多個線程之間共享。
4) JVM 語言棧
Java 語言堆棧存儲局部變量,和部分結(jié)果,每個線程都有自己的 JVM 堆棧,在創(chuàng)建線程時同時創(chuàng)建。每當(dāng)調(diào)用方法時都會創(chuàng)建一個新的,并在方法調(diào)用過程完成時將其刪除。
5) PC 寄存器
PC 寄存器存儲當(dāng)前正在執(zhí)行的 Java 虛擬機(jī)指令的地址。在 Java 中,每個線程都有其獨(dú)立的 PC 寄存器。
6) 本地方法棧
本機(jī)方法棧持有本機(jī)代碼的指令取決于本機(jī)庫。它是用另一種語言而不是 Java 編寫的。
7) 執(zhí)行引擎
它是一種用于測試硬件、軟件或完整系統(tǒng)的軟件。測試執(zhí)行引擎從不攜帶有關(guān)被測產(chǎn)品的任何信息。
8) 本地方法接口
本機(jī)方法接口是一個編程框架。它允許在 JVM 中運(yùn)行的 Java 代碼由庫和本機(jī)應(yīng)用程序調(diào)用。
9) 本地方法庫
本機(jī)庫是執(zhí)行引擎所需的本機(jī)庫(C、C++)的集合。
軟件代碼編譯執(zhí)行流程
為了編寫和執(zhí)行軟件程序,您需要以下內(nèi)容
1) 編輯器 – 要輸入您的程序,可以使用記事本。
2) 編譯器 ——將您的高級語言程序轉(zhuǎn)換為本地機(jī)器代碼。
3) 鏈接器 ——將主程序中的不同程序文件引用組合在一起。
4) Loader – 將您的輔助存儲設(shè)備(如硬盤、閃存驅(qū)動器、CD )中的文件加載到 RAM 中以供執(zhí)行。執(zhí)行代碼時會自動完成加載。
5) 執(zhí)行– 由您的操作系統(tǒng)和處理器處理的代碼的實(shí)際執(zhí)行。
C代碼編譯執(zhí)行過程
了解Java中的Java編譯過程。首先讓我們快速了解一下 C 中的編譯和鏈接過程。
假設(shè)在 main 中,您調(diào)用了兩個函數(shù) f1 和 f2。main 函數(shù)存儲在文件 a1.c 中。
函數(shù) f1 存儲在文件 a2.c 中
函數(shù) f2 存儲在文件 a3.c 中
所有這些文件,即 a1.c、a2.c 和 a3.c,都被提供給編譯器。其輸出是相應(yīng)的目標(biāo)文件,即機(jī)器代碼。
下一步是在鏈接器的幫助下將所有這些目標(biāo)文件集成到一個 .exe 文件中。鏈接器會將所有這些文件組合在一起并生成 .exe 文件。
在程序運(yùn)行過程中,加載程序會將 a.exe 加載到 RAM 中執(zhí)行。
Java VM 中的 Java 代碼編譯和執(zhí)行
讓我們看看 JAVA 的編譯執(zhí)行過程。在您的主文件中,您有兩個方法 f1 和 f2。
- main方法存放在文件a1.java中
- f1 作為 a2.java 存儲在文件中
- f2 作為 a3.java 存儲在文件中
編譯器將編譯這三個文件,并生成 3 個對應(yīng)的 .class 文件,其中包含字節(jié)碼。與 C 不同,沒有進(jìn)行鏈接。Java VM 或 Java 虛擬機(jī)駐留在 RAM 上。在執(zhí)行期間,使用類加載器將類文件帶到 RAM 中。字節(jié)碼已驗(yàn)證是否存在任何安全漏洞。
接下來,執(zhí)行引擎會將字節(jié)碼轉(zhuǎn)換為本地機(jī)器碼。這只是及時編譯,這是Java相對較慢的主要原因之一。
注意:JIT或即時編譯器是 Java 虛擬機(jī) (JVM) 的一部分。它同時轉(zhuǎn)化具有相似功能的部分字節(jié)碼。
為什么Java既是解釋型語言又是編譯型語言?
編程語言被分類為
- 高級語言,例如C++、Java
- 中級語言,例如C
- 低級語言,例如匯編
- 最后是最低級別的機(jī)器語言。
編譯器是一個程序,它把程序從一個級別轉(zhuǎn)化到另外一個級別(一般是從高到低),比如把C++ 程序轉(zhuǎn)化到機(jī)器碼。
java編譯器將高級java代碼轉(zhuǎn)換成字節(jié)碼(也是一種機(jī)器碼)。
解釋器是一個程序,它把程序轉(zhuǎn)化為相同等級的其他語言,比如把Java程序轉(zhuǎn)換成C++。
在 Java 中,Jit生成器將字節(jié)碼轉(zhuǎn)換為處于相同級別的本機(jī)機(jī)器代碼,因此,Java 既是編譯型語言,又是解釋型語言。
為什么 Java 很慢?
Java 運(yùn)行緩慢的兩個主要原因是
動態(tài)鏈接:與 C 不同,鏈接是在運(yùn)行時完成的,每次程序在 Java 中運(yùn)行時。
運(yùn)行時解釋器:字節(jié)碼到本地機(jī)器碼的轉(zhuǎn)換是在 Java 運(yùn)行時完成的,這進(jìn)一步減慢了速度。
但是,最新版本的 Java 在很大程度上解決了性能瓶頸。
總結(jié):
- JVM 的完整形式是Java Virtual Machine.(Java虛擬機(jī)),Java 中的 JVM 是驅(qū)動 Java 代碼的引擎,它將 Java 字節(jié)碼轉(zhuǎn)換為機(jī)器語言。
- Java 中的 JVM 架構(gòu)包含類加載器、內(nèi)存區(qū)、執(zhí)行引擎等。
- 在 JVM 中,Java 代碼被編譯為字節(jié)碼。這個字節(jié)碼在不同的機(jī)器上被解釋成不同的機(jī)器碼。
- JIT 代表即時編譯器。JIT 是 Java 虛擬機(jī) (JVM) 的一部分。它用于加快執(zhí)行時間。
- 與其他編譯器機(jī)器相比,Java 中的 JVM 執(zhí)行速度可能較慢。