通俗講解JVM的類載入機制

2022-09-29 16:27:15 字數 3339 閱讀 3139

前言

我們很多小夥伴平時都是做j**a開發的,那麼作為一名合格的工程師,你是否有仔細的思考過jvm的執行原理呢。

如果懂得了jvm的執行原理和記憶體模型,像是一些jvm調優、垃圾**機制等等的問題我們才能有乙個更清晰的概念。

為了走進jvm,深入了解底層,王子打算寫乙個jvm的專題,留下自己對jvm探索的足跡,同時也希望能幫到小夥伴們更好的理解jvm。

那我們開始吧。

j**a**的執行流程

首先我們就來聊一聊j**a**是怎麼執行起來的,這部分比較基礎相信大家都知道,就當成是個複習吧。

我們編寫的**都是在j**a檔案中編寫的,然後會編譯成class位元組碼檔案。

當我們使用到哪個類的時候就會通過類載入器把class位元組碼檔案中的類載入到jvm記憶體中,然後就是在jvm記憶體中執行我們的**了。

整體的執行流程就是這樣,相信小夥伴們都很清楚這些,但是有關類載入器是如何把類載入到jvm記憶體中的,小夥伴們有考慮過嗎?

今天我們主要就是聊這一部分。

jvm什麼時候載入類

其實說到類載入的底層機制,這是乙個很複雜的過程,但是對於我們平時的工作來講,只要懂得它的核心原理就可以了。

乙個類的載入過程會經歷如下的幾個過程:

載入、驗證、準備、解析、初始化、使用、解除安裝

首先我們就先弄明白乙個問題,jvm是什麼時候去載入類的呢?

其實答案很簡單,就是我們什麼時候使用到了這個類,它就去class位元組碼檔案中去載入這個類。

而作為程式的入口,具有main方法的類,肯定是最開始的時候就載入到jvm中了。

對於載入類的時間點問題,其實就是這麼簡單。

類載入器和雙親委派機制

既然我們知道了類載入的時間點,那麼jvm是通過什麼方式對類進行載入的呢?就是類載入器。

那接下來我們就來聊聊jvm的類載入器。

jvm的類載入器總體上可以分成4層,我們一起看一下。

1.啟動類載入器

首先就是jvm啟動的第一道關口,啟動類載入器bootstrap classloader,它主要是載入j**a的核心類。

相信大家都知道,無論是什麼環節下執行j**a程式,都是要安裝jvm虛擬機器環境的,而在這個環境的目錄中是有乙個lib資料夾的,這個檔案下就是j**a最核心的類庫,支撐著j**a系統的執行。

所以一旦jvm啟動,那麼首先就會通過啟動類載入器去載入lib資料夾下的核心類庫。

2.擴充套件類載入器

然後我們就到了第二層,擴充套件類載入器extension classloader,這個類載入器其實與啟動類載入器是類似的。

在我們的jvm虛擬機器環境目錄下,是有乙個lib/ext的資料夾的,這裡面的類就是j**a執行環境的一些擴充套件類,這些擴充套件類就是在jvm啟動後,通過擴充套件類載入器進行載入的。

3.應用程式類載入器

載入完核心類庫和擴充套件類,這時候就到了第三層,應用程式類載入器application classloader,這個類載入器你就可以理解成是載入我們寫好的j**a**的就可以了。

4.自定義類載入器

前面的三層就是基本的類載入器了,然後第四層是自定義類載入器,根據一些特殊的需求來自己定義類載入器載入我們的類。

整體上類載入器就是這麼的4層結構。很多小夥伴可能都聽說過雙親委派機制,那麼什麼是雙親委派機制呢,王子就和大家用最接地氣的語言描述一下。

其實很好理解,就是當我們的類載入器要載入乙個類的時候,它首先會委派給它的父親去載入,但是如果它的父親沒找到就會把這個事交給他的孩子自己去完成了。

這就是雙親委派機制。

舉個例子,假如我們的應用程式類載入器要載入乙個類a,那麼首先它會先回家找它老爸擴充套件類載入器,問問「老爸,你那有這個類a嗎?」

然後擴充套件類載入器接到這個請求之後,同樣也懶得處理,再去找它爺爺啟動類載入器。

它爺爺找了一圈沒找到類a,很生氣,就對擴充套件類載入器說,「我這沒有,你自己找去!」

然後擴充套件類載入器就灰溜溜的自己找了一圈,同樣也沒找到,這時候就找到應用類載入器了,說:「我這哪有你這個類a,這明明是你自己應該幹的活,愛上哪找上哪找去,我不管了」。

這時候應用類載入器就只能自己去處理了,找了一圈發現找到了類a,就把它載入到jvm記憶體中了。

相信大家看了這個例子應該很容易理解了吧。

所以假設我們自己建立了乙個類j**a.lang程式設計客棧.string,它是不會被應用類載入器載入到記憶體中的,因為父類中可以找到這個類,就直接給載入到記憶體中了。

聊聊驗證、準備、程式設計客棧解析、初始化階段

聊完了載入,我們再來看看驗證、準備、解析、初始化這幾個階段jvm都做了什麼。

1.驗證階段

這一步其實很容易理解,就是jvm根據j**a規範,來校驗你載入進來的class檔案中的內容是否符合規範,如果不符合規範jvm是無法正常執行的。

所以在載入後,首先就是驗證階段。

2.準備階段

假設我們有乙個類a,剛剛載入並通過了驗證,那麼就會進行準備工作。

這個準備工作其實就是給類a分配一定的記憶體空間,然後給裡面的靜態變數(static修飾的變數)也分配記憶體空間,並賦初始值。

3.解析階段

這個階段幹的事實際上是把符號引用替換為直接引用,這一過程網上有很多資料,還是比較複雜的,如果感興趣小夥伴們可以自己查閱一下資料。

實際工作中也很少會接觸這部分的內容,所以我們知道有這麼個階段就可以了。

4.初始化階段

在準備階段,我們把類a的記憶體已經分配完了,那麼初始化階段要做些什麼事呢?我們先看一下類a的**

public class a

準備階段我們只是給變數i分配了記憶體空間,並賦值了初始值,但是後邊的system.getproperty("i")是不會執行的。

沒錯,這部分**就是在初始化階段執行的,另外靜態**塊也會在這一階段執行。

舉個例子,比如我們新建乙個物件new a(),此時就會觸發從載入到初始化的全過程,把這個類準備好並建立乙個例項物件。

此外這裡有乙個規則,如果類a繼承了類b,那麼在初始化類a的時候,如果發現類b還沒有初始化,會先初始化類b。

擴充套件到這裡關於jvm的類載入機制其實就已經說完了,王子再給大家擴充套件乙個小知識點。

小夥伴們想過沒有,tomcat也是用j**a開發的,那麼它的類載入機制是什麼樣的呢,為什麼就能支援jsp呢?

其實它就是利用了程式設計客棧自定義類載入器這一機制,自己自定義了很多類載入器,整體的結構如下:

tomcat自定義了這麼多的類載入器,用來載入它自己的核心類庫,並且tomcat是打破了雙親委派機制的,感興趣的小夥伴可以自己去查資料了解一下,王子就不在本篇文章長篇大論來聊tomcat了。

總結今天我們聊的內容還是jvm中比較基礎的部分,以後的文章我們再慢慢深入,去探索jvm的底層原理,如果對jvm感興趣的小夥伴可以關注王子的後續文章哦,我們可以一步乙個腳印的逐步分解jvm,去了解jvm的垃圾**機制、效能調優等等實用性問題,讓你面對jvm的面試或者生產實踐也可以游刃有餘。

那我們下次見。

JVM 類載入機制

1 載入步驟 jvm 類載入機制分為五個部分 載入,驗證,準備,解析,初始化。2 類載入器 3 雙親委派 1 什麼是雙親委派?當乙個類收到了類載入請求,他首先把這個請求委派給父類去完成,每乙個層次類載入器都是如此,因此所有的載入請求都應該傳送到啟動類載入其中,只有當父類載入器反饋自己無法完成這個請求...

Jvm類載入機制

類載入的過程 類載入器 控制台列印輸出 主要分為以下三步 載入源包括很多種,如檔案 class檔案,jar檔案 網路 計算生成的乙個二進位製流 proxy 由其他檔案生成 jsp 等,資料庫 準備階段正式為類變數分配記憶體並設定變數的初始值。這些變數使用的記憶體都將在方法區中進行分配 這裡的初始值並...

JVM類載入機制

jvm類載入總共有7個階段。載入 驗證 準備 解析 初始化 使用 解除安裝。主要需要了解的為準備階段,初始化階段。下面分別對此兩個階段進行解析。初始化階段 初始化分為主動引用和被動引用。主動引用包括 1 建立類的例項 2 訪問類的靜態變數 3 訪問類的靜態方法 4 反射 5 虛擬機器啟動時,定義了m...