圖解JVM整體結(jié)構(gòu)、執(zhí)行流程以及兩種架構(gòu)模型,你學(xué)會(huì)了嗎?
JVM整體結(jié)構(gòu)

- HotSpot VM 是目前市面上高性能虛擬機(jī)的代表作之一。
- 方法區(qū)和堆:多線程共享
- 虛擬機(jī)棧、本地方法棧、程序計(jì)數(shù)器:每個(gè)線程獨(dú)有一份
- 執(zhí)行引擎:包含三部分:解釋器,及時(shí)編譯器(后端編譯器),垃圾回收器
- 它采用解釋器與即時(shí)編譯器并存的架構(gòu)。
- 在今天,Java 程序的運(yùn)行性能早已脫胎換骨,已經(jīng)達(dá)到了可以和 C/C++ 程序一較高下的地步。

Java 代碼執(zhí)行流程

只是能生成被 Java 虛擬機(jī)所能解釋的字節(jié)碼文件,那么理論上就可以自己設(shè)計(jì)一套代碼了
解釋器:保證相應(yīng)時(shí)間,負(fù)責(zé)解釋執(zhí)行的速度
JIT編譯器:負(fù)責(zé)編譯的性能,針對字節(jié)碼指令,熱點(diǎn)代碼,放在方法區(qū)緩存起來,下次遇見直接變成二進(jìn)制指令
JVM 的架構(gòu)模型
Java 編譯器輸入的指令流基本上是一種基于棧的指令集架構(gòu),另外一種指令集架構(gòu)則是基于寄存器的指令集架構(gòu)。
具體來說:這兩種架構(gòu)之間的區(qū)別:
基于棧式架構(gòu)
- 設(shè)計(jì)和實(shí)現(xiàn)更簡單,適用于資源受限的系統(tǒng);
- 避開了寄存器的分配難題:使用零地址指令方式分配。
- 指令流中的指令大部分是零地址指令,其執(zhí)行過程依賴于操作棧。指令集更小,編譯器容易實(shí)現(xiàn)。
- 不需要硬件支持,可移植性更好,更好實(shí)現(xiàn)跨平臺(tái)
基于寄存器架構(gòu)
- 典型的應(yīng)用是 x86 的二進(jìn)制指令集:比如傳統(tǒng)的 PC 以及 Android 的 Davlik 虛擬機(jī)。
- 指令集架構(gòu)則完全依賴硬件,可移植性差
- 性能優(yōu)秀和執(zhí)行更高效
- 花費(fèi)更少的指令去完成一項(xiàng)操作。
- 在大部分情況下,基于寄存器架構(gòu)的指令集往往都以一地址指令、二地址指令和三地址指令為主,而基于棧式架構(gòu)的指令集卻是以零地址指令為主
舉例
同樣執(zhí)行2+3這種邏輯操作,其指令分別如下:
基于棧的計(jì)算流程(以Java虛擬機(jī)為例):
- iconst_2 // 常量2入棧
- istore_1
- iconst_3 // 常量3入棧
- istore_2
- iload_1
- iload_2
- iadd //常量2/3出棧,執(zhí)行相加
- istore_0 // 結(jié)果5入棧
而基于寄存器的計(jì)算流程
- mov eax,2 //將eax寄存器的值設(shè)為
- 1add eax,3 //使eax寄存器的值加3
字節(jié)碼反編譯
我們編寫一個(gè)簡單的代碼,然后查看一下字節(jié)碼的反編譯后的結(jié)果
- public class StackStruTest {
- public static void main(String[] args) {
- int i = 2 + 3;
- }
- }
然后我們找到編譯后的 class 文件,使用下列命令進(jìn)行反編譯
- javap -v(verbose) StackStruTest.class
得到的文件為:
- public static void main(java.lang.String[]);
- descriptor: ([Ljava/lang/String;)V
- flags: ACC_PUBLIC, ACC_STATIC
- Code:
- stack=2, locals=4, args_size=1
- 0: iconst_2
- 1: istore_1
- 2: iconst_3
- 3: istore_2
- 4: iload_1
- 5: iload_2
- 6: iadd
- 7: istore_3
- 8: return
- LineNumberTable:
- line 9: 0
- line 10: 2
- line 11: 4
- line 12: 8
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 9 0 args [Ljava/lang/String;
- 2 7 1 i I
- 4 5 2 j I
- 8 1 3 k I
總結(jié)
由于跨平臺(tái)性的設(shè)計(jì),Java 的指令都是根據(jù)棧來設(shè)計(jì)的。
不同平臺(tái) CPU 架構(gòu)不同,所以不能設(shè)計(jì)為基于寄存器的。
優(yōu)點(diǎn)是跨平臺(tái),指令集小,編譯器容易實(shí)現(xiàn)
缺點(diǎn)是性能下降,實(shí)現(xiàn)同樣的功能需要更多的指令。
時(shí)至今日,盡管嵌入式平臺(tái)已經(jīng)不是 Java 程序的主流運(yùn)行平臺(tái)了(準(zhǔn)確來說應(yīng)該是 HotSpotVM 的宿主環(huán)境已經(jīng)不局限于嵌入式平臺(tái)了),那么為什么不將架構(gòu)更換為基于寄存器的架構(gòu)呢?
總結(jié):因?yàn)橐呀?jīng)夠用了
棧
跨平臺(tái)性
指令集小
指令多
執(zhí)行性能比寄存器差