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