JVM 整體架構(gòu)
1. 前言
本節(jié)內(nèi)容主要是介紹 JVM 的整體架構(gòu),對(duì) JVM 有一個(gè)宏觀的認(rèn)識(shí),是本套課程的基礎(chǔ)知識(shí)部分,雖然為基礎(chǔ)知識(shí),但是對(duì)整體架構(gòu)的理解,是學(xué)習(xí) JVM 課程的前提,所以要重視本節(jié)的內(nèi)容學(xué)習(xí)。本節(jié)主要知識(shí)點(diǎn)如下:
- 認(rèn)識(shí) JVM 整體結(jié)構(gòu),對(duì) JVM 的各個(gè)模塊作用有一個(gè)初步的了解,為本節(jié)基礎(chǔ)內(nèi)容;
- 對(duì)「類加載子系統(tǒng)模塊」,進(jìn)行更加細(xì)粒度的模塊劃分介紹,重點(diǎn)從概念層面掌握類加載的步驟,為本節(jié)重點(diǎn)內(nèi)容之一;
- 對(duì)「運(yùn)行時(shí)數(shù)據(jù)區(qū)」進(jìn)行更加細(xì)粒度的模塊劃分介紹,重點(diǎn)先從概念層面,了解運(yùn)行時(shí)數(shù)據(jù)區(qū)的五大模塊定義及作用,為本節(jié)重點(diǎn)內(nèi)容之一;
- 對(duì)「執(zhí)行引擎」進(jìn)行更加細(xì)粒度的模塊劃分介紹,重點(diǎn)先從概念層面,了解執(zhí)行引擎的三大模塊定義及作用,其中包括垃圾回收器的初步介紹,為本節(jié)重點(diǎn)內(nèi)容之一;
- 了解 JVM 的生命周期,可視作本節(jié)課程的次重點(diǎn)內(nèi)容。
本節(jié)內(nèi)容是我們初次了解 JVM 整體架構(gòu),以及各模塊的定義及作用,從概念的角度去了解 JVM 的各個(gè)模塊,為我們后續(xù)對(duì)各模塊的深入學(xué)習(xí)打下了良好的基礎(chǔ)。
2. JVM 整體架構(gòu)
我們首先來看看,JVM 的整體結(jié)構(gòu)圖,然后對(duì)每一個(gè)結(jié)構(gòu)模塊進(jìn)行簡單的介紹。
從結(jié)構(gòu)中可以看出,JVM 結(jié)構(gòu)主要分為以上幾個(gè)模塊,其中部分重點(diǎn)模塊內(nèi)部還會(huì)細(xì)分責(zé)任更加明細(xì)的模塊,此處先來簡單了解下每個(gè)模塊的作用。
- Class 文件:主要指編譯成字節(jié)碼的 Java 文件,Class 文件才是 JVM 可以識(shí)別的文件,所以 Java 文件需要先進(jìn)行編譯才可進(jìn)入 JVM 執(zhí)行;
- 類加載子系統(tǒng):類的加載,主要負(fù)責(zé)從文件系統(tǒng),或者網(wǎng)絡(luò)中加載 Class 信息,并與運(yùn)行時(shí)數(shù)據(jù)區(qū)進(jìn)行交互;
- 運(yùn)行時(shí)數(shù)據(jù)區(qū):主要包括五個(gè)小模塊,Java 堆, Java 棧,本地方法棧,方法區(qū),寄存器。后文對(duì)細(xì)節(jié)模塊會(huì)有概念的介紹;
- 執(zhí)行引擎:分配給運(yùn)行時(shí)數(shù)據(jù)區(qū)的字節(jié)碼將由執(zhí)行引擎執(zhí)行,執(zhí)行引擎讀取字節(jié)碼并逐個(gè)執(zhí)行。垃圾回收器就是執(zhí)行引擎的一部分;
- 本地方法接口:本機(jī)方法庫進(jìn)行交互,并提供執(zhí)行引擎所需的本機(jī)庫;
- 本地方法庫:它是執(zhí)行引擎所需的本機(jī)庫的集合。
通過上文對(duì)JVM 整體結(jié)構(gòu)的介紹,我們對(duì)JVM有了一定的認(rèn)識(shí)。但是對(duì)于上圖所示的JVM 整體架構(gòu)圖,還是感覺很抽象,感覺并不直觀。那么我們?cè)倮^續(xù)看下圖,通過 6 個(gè)步驟,來簡單的描述下,一個(gè) Java 文件在 JVM 中的流轉(zhuǎn)過程。
我們對(duì)上圖中的 6 個(gè)步驟,逐一進(jìn)行介紹:
- 步驟 1 : 我們的 Demo.java 文件,通過 JDK 的 javac 命令,成功的被編譯成為額 Demo.class 文件;
- 步驟 2 :JVM 有自己的類加載器,將編譯好的 Demo.class文件進(jìn)行了加載;
- 步驟 3 :類加載器將加載的 Demo.class文件投放到了運(yùn)行時(shí)數(shù)據(jù)區(qū),供程序執(zhí)行使用;
- 步驟 4 :運(yùn)行時(shí)數(shù)據(jù)區(qū)將字節(jié)碼文件,交給執(zhí)行引擎執(zhí)行;
- 步驟 5 :執(zhí)行引擎執(zhí)行完畢,會(huì)對(duì)運(yùn)行時(shí)數(shù)據(jù)區(qū)的數(shù)據(jù)進(jìn)行操作,比如說垃圾回收機(jī)制是執(zhí)行引擎的一部分,垃圾回收機(jī)制,針對(duì)的是運(yùn)行時(shí)數(shù)據(jù)區(qū)的堆空間,后續(xù)我們會(huì)詳細(xì)講解;
- 步驟 R :我們發(fā)現(xiàn)圖中有很多步驟 R ,此處 R 代表 Random,即隨機(jī)發(fā)生的步驟。其實(shí)就是我們?cè)趫?zhí)行過程中的一個(gè)本地方法的調(diào)用,只要我們的程序在運(yùn)行過程中需要調(diào)用本地方法,那么步驟R就會(huì)發(fā)生。
Tips:此處僅僅是一個(gè)簡要的介紹,后文會(huì)對(duì)重點(diǎn)部分進(jìn)行更加細(xì)粒度的模塊介紹。此處需要同學(xué)記住整體 JVM 結(jié)構(gòu)框架,方便后續(xù)知識(shí)的學(xué)習(xí)。
3. 類加載子系統(tǒng)
Java 的動(dòng)態(tài)類加載功能由類加載器子系統(tǒng)處理,處理過程包括加載、鏈接和初始化。如下圖所示,展現(xiàn)了類加載子系統(tǒng)的處理過程。
我們來介紹下上圖中類加載子系統(tǒng)的三個(gè)步驟:
加載:通過三種不同的類加載器對(duì) Class 文件進(jìn)行加載,后續(xù)章節(jié)會(huì)對(duì)三種類加載器單獨(dú)進(jìn)行講解。我們也可以自定義類加載器,通過復(fù)寫 classLoader 方法可以實(shí)現(xiàn)自定義的類加載器。
鏈接:鏈接階段會(huì)對(duì)加載好的 Class 文件進(jìn)行字節(jié)碼、靜態(tài)變量、方法引用等進(jìn)行驗(yàn)證和解析,為初始化做準(zhǔn)備。
初始化:類加載的最后階段,對(duì)類進(jìn)行初始化。
Tips:類加載子系統(tǒng)是非常復(fù)雜的,其實(shí)加載(Loading)和鏈接(Linking)部分還能夠進(jìn)行更加細(xì)致的過程劃分。鑒于我們剛剛接觸 JVM,此處點(diǎn)到即止。不過不用擔(dān)心,后續(xù)的章節(jié)會(huì)對(duì)加載(Loading)和鏈接(Linking)這兩個(gè)部分進(jìn)行更加細(xì)粒度的劃分以及更加細(xì)致的講解,我們循序漸進(jìn),步步為營。
4. 運(yùn)行時(shí)數(shù)據(jù)區(qū)
如下圖運(yùn)行時(shí)數(shù)據(jù)區(qū)共包含如下 5 個(gè)模塊,方法區(qū),Java 棧,本地方法棧,堆和程序計(jì)數(shù)器。
Tips:方法區(qū)和堆為共享內(nèi)存區(qū)域,多線程環(huán)境下共享這兩塊內(nèi)存區(qū)域。 Java 棧,本地方法棧和程序計(jì)數(shù)器為線程私有部分,私有數(shù)據(jù)對(duì)其他線程不可見。
我們下邊來介紹下運(yùn)行時(shí)數(shù)據(jù)區(qū)的五個(gè)模塊:
-
方法區(qū)(Method Area):所有的類級(jí)數(shù)據(jù)將存儲(chǔ)在這里,包括靜態(tài)變量。每個(gè) JVM 只有一個(gè)方法區(qū),它是一個(gè)共享資源;
-
堆區(qū)域(Heap Area):所有對(duì)象及其對(duì)應(yīng)的實(shí)例變量和數(shù)組將存儲(chǔ)在這里。每個(gè) JVM 也只有一個(gè)堆區(qū)域。由于方法和堆區(qū)域共享多個(gè)線程的內(nèi)存,所存儲(chǔ)的數(shù)據(jù)不是線程安全的;
-
棧區(qū)(Stack Area):對(duì)于每個(gè)線程,將創(chuàng)建單獨(dú)的運(yùn)行時(shí)棧。對(duì)于每個(gè)方法調(diào)用,將在棧存儲(chǔ)器中產(chǎn)生一個(gè)條目,稱為棧幀。所有局部變量將在棧內(nèi)存中創(chuàng)建。棧區(qū)域是線程安全的,因?yàn)樗还蚕碣Y源;
-
PC寄存器(PC Registers):也稱作程序計(jì)數(shù)器。每個(gè)線程都有單獨(dú)的 PC 寄存器,用于保存當(dāng)前執(zhí)行指令的地址。一旦執(zhí)行指令,PC 寄存器將被下一條指令更新;
-
本地方法棧(Native Method stacks):本地方法棧保存本地方法信息。對(duì)于每個(gè)線程,將創(chuàng)建一個(gè)單獨(dú)的本地方法棧。
5. 執(zhí)行引擎
如下圖執(zhí)行引擎共包含如下三個(gè)模塊,解釋器,JIT 編譯器和垃圾回收器。
Tips:垃圾回收器是本模塊的重中之重,也是 JVM 的重中之重。后續(xù)會(huì)有專門的小節(jié)內(nèi)容對(duì)垃圾回收器進(jìn)行細(xì)致的講解。
我們下邊來介紹下執(zhí)行引擎的三個(gè)模塊:
-
解釋器:解釋器是作用于字節(jié)碼的解釋。解釋器的缺點(diǎn)是當(dāng)一個(gè)方法被調(diào)用多次時(shí),每次都需要一個(gè)新的解釋;
-
JIT 編譯器:JIT 編譯器消除了解釋器的缺點(diǎn)。執(zhí)行引擎將在轉(zhuǎn)換字節(jié)碼時(shí)使用解釋器的幫助,但是當(dāng)它發(fā)現(xiàn)重復(fù)的代碼時(shí),將使用 JIT 編譯器,這提高了系統(tǒng)的性能;
-
垃圾回收器(Garbage Collector):收集和刪除未引用的對(duì)象。可以通過調(diào)用
System.gc()
觸發(fā)垃圾收集。
6. 小結(jié)
本節(jié)主要是對(duì) JVM 的整體框架進(jìn)行介紹,了解整體架構(gòu)是學(xué)習(xí) JVM 的基本前提。后續(xù)我們會(huì)對(duì)每一個(gè)模塊進(jìn)行展開講解,所有的知識(shí)點(diǎn)都是圍繞 JVM 的架構(gòu)展開的,本節(jié)內(nèi)容非常重要,一定要認(rèn)真的學(xué)習(xí)。