欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳細(xì)分析JVM類加載機(jī)制

 更新時(shí)間:2022年04月27日 09:02:54   作者:羨羨ˇ  
JVM將class文件字節(jié)碼文件加載到內(nèi)存中,?并將這些靜態(tài)數(shù)據(jù)轉(zhuǎn)換成方法區(qū)中的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu),在堆(并不一定在堆中,HotSpot在方法區(qū)中)中生成一個(gè)代表這個(gè)類的java.lang.Class?對(duì)象,作為方法區(qū)類數(shù)據(jù)的訪問入口,接下來將詳細(xì)講解JVM類加載機(jī)制

前言

        ladies and gentleman , 你們好?? ,我是羨羨 , 這節(jié)我們進(jìn)入jvm的學(xué)習(xí) , 我們知道 , jvm是java虛擬機(jī), java代碼的執(zhí)行與 jvm 息息相關(guān), 接下來我們來依次介紹 , 首先這節(jié)先來介紹 jvm 中的類加載部分

1. jvm 的組成

jvm組成可分為這四個(gè)部分

1.類加載器(ClassLoader)

2.運(yùn)行時(shí)數(shù)據(jù)區(qū)(Runtime Data Area)

3.執(zhí)行引擎(ExecutionEngine)

4.本地庫接口(Native Interface)

那么一個(gè)程序在 jvm 中的運(yùn)行過程是怎樣的呢? 

       java代碼首先被編譯成字節(jié)碼文件(Class文件),  通過不同操作系統(tǒng)上的 jvm 來加載解釋 , 這個(gè)過程首先需要類加載器加載class文件 , 然后進(jìn)行字節(jié)碼校驗(yàn) , 校驗(yàn)結(jié)束通過后通過jvm解釋器翻譯成機(jī)器碼交給操作系統(tǒng)執(zhí)行

      程序在執(zhí)行之前先要把 java 代碼轉(zhuǎn)換成字節(jié)碼(class 文件),jvm 首先需要把字節(jié)碼通一定的方式 類加載器(ClassLoader) 把文件加載到內(nèi)存中的運(yùn)行時(shí)數(shù)據(jù)區(qū)(Runtime DataArea) ,而字節(jié)碼文件是 jvm 的一套指 令集規(guī)范,并不能直接交個(gè)底層操作系統(tǒng)去執(zhí)行,因此需要特定的命令解析器 執(zhí)行引擎(Execution Engine) 將字節(jié)碼翻譯成底層系統(tǒng)指令再交由 CPU 去執(zhí)行,而這個(gè)過程中需要調(diào)用其他語言的接口 本地庫接口(Native Interface) 來實(shí)現(xiàn)整個(gè)程序的功能,這就是這 4 個(gè)主要組成部分的職責(zé)與功能

jvm整體結(jié)構(gòu)如下圖

 可能說到這里 , 初學(xué)的同學(xué)會(huì)有點(diǎn)懵 , 不過不用擔(dān)心, 上圖中的各個(gè)組成部分后面都會(huì)一一解釋

2. 類加載

       通過上面 jvm的運(yùn)行過程可知 , 類加載就是讀取 class文件的過程 , 這期間需要用到類加載器 , 類加載器只負(fù)責(zé)加載 , 至于如何執(zhí)行 , 則由執(zhí)行引擎決定

類加載 又分為以下幾個(gè)模塊

      類加載器加載class文件到 jvm中 , 被稱為DNA元數(shù)據(jù)模板 , jvm通過模板來創(chuàng)建實(shí)例 , 類加載器在此過程相當(dāng)于擔(dān)任了快遞員的角色

那么類加載的過程是怎樣的呢 ?

可以看到 , 分為三個(gè)過程 : 加載, 鏈接 ,初始化 

1. 加載  

1. 通過類名(地址)獲取此類的二進(jìn)制字節(jié)流.

2. 將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)換為方法區(qū)(元空間)的運(yùn)行時(shí)結(jié)構(gòu).

3. 在內(nèi)存中生成一個(gè)代表這個(gè)類的 java.lang.Class 對(duì)象,作為這個(gè)類的各種數(shù)據(jù)的訪問入口.

 顧名思義 , 加載就是把類中的信息加載進(jìn) jvm 中

2. 鏈接

 鏈接又分為 3 個(gè)過程 : 驗(yàn)證, 準(zhǔn)備 ,解析

(1) . 驗(yàn)證

檢驗(yàn)被加載的類是否有正確的內(nèi)部結(jié)構(gòu),并和其他類協(xié)調(diào)一致

        驗(yàn)證文件格式是否一致: class 文件在文件開頭有特定的文件標(biāo)識(shí)(字節(jié)碼文件都以 CA FE BA BE 標(biāo)識(shí)開頭);主,次版本號(hào)是否在當(dāng)前 java 虛擬機(jī)接收范圍內(nèi)

       元數(shù)據(jù)驗(yàn)證:對(duì)字節(jié)碼描述的信息進(jìn)行語義分析,以保證其描述的信息符合java 語言規(guī)范的要求,例如這個(gè)類是否有父類;是否繼承瀏覽不允許被繼承的類(final 修飾的類)

驗(yàn)證過程主要是看是否符合java語言的規(guī)范

(2) . 準(zhǔn)備

準(zhǔn)備:準(zhǔn)備階段則負(fù)責(zé)為類的靜態(tài)屬性分配內(nèi)存,并設(shè)置默認(rèn)初始值(int為0)

此過程不包含用 final 修飾的 static 常量(靜態(tài)常量),在編譯時(shí)進(jìn)行初始化.

//準(zhǔn)備階段值為0
public static int value = 123;
//準(zhǔn)備階段值為123
public static final int value = 123;

(3) .解析

    將類的二進(jìn)制數(shù)據(jù)中的符號(hào)引用替換成直接引用(符號(hào)引用是 Class 文件的邏輯符號(hào),直接引用指向的方法區(qū)中某一個(gè)地址)

      將符號(hào)引用替換成直接引用, 這句話怎么理解呢 ? 這里來舉個(gè)例子

public void method1(){
    method2();
}

        在 方法1 中調(diào)用 方法2 , 我們這樣來寫代碼的時(shí)候, 這就只是符號(hào)引用 , 而當(dāng)這段程序被加載進(jìn) jvm解析的時(shí)候 符號(hào)引用就會(huì)變成直接引用, 也就是指明此處真正的引用地址

3. 初始化

 在談?lì)惖某跏蓟^程之前, 先來考慮 , 類什么時(shí)候會(huì)被初始化? 

1 )創(chuàng)建類的實(shí)例,也就是 new 一個(gè)對(duì)象

2)訪問某個(gè)類或接口的靜態(tài)變量,或者對(duì)該靜態(tài)變量賦值

3)調(diào)用類的靜態(tài)方法

4)反射(Class.forName(“”))

5)初始化一個(gè)類的子類(會(huì)首先初始化子類的父類)

       初始化類的過程也是為類中成員賦值的過程 , 在鏈接過程中的準(zhǔn)備過程中被static修飾的變量是賦了默認(rèn)值(int型為0), 而在初始化過程中才會(huì)賦予我們賦的值

       我們常說 , 用 static 修飾的變量, 方法 , 代碼塊是跟類直接打交道的 , 我們說加載類的時(shí)候, 使用static修飾的成員也會(huì)被加載 , 此過程也是在類的初始化中完成

那么在初始化過程中, 賦值順序是怎樣的呢?

      如果同時(shí)包含多個(gè)靜態(tài)變量和靜態(tài)代碼塊,則按照自上而下的順序依次執(zhí)行。 如果初始化一個(gè)類的時(shí)候,其父類尚未初始化,則優(yōu)先初始化其父類。

      順序是:父類 static –> 子類 static –> 父類構(gòu)造方法- -> 子類構(gòu)造方法

下面代碼 num 的值變化

3. 類加載器

        從開發(fā)人員的角度上來講, 類加載器可分為3類 : 引導(dǎo)類加載器(啟動(dòng)類加載器), 擴(kuò)展類加載器 , 應(yīng)用程序類加載器

引導(dǎo)類加載器(啟動(dòng)類加載器)

     這個(gè)類加載器使用 C/C++語言實(shí)現(xiàn),嵌套在 JVM 內(nèi)部.它用來加載 java 核心類庫.     

     并不繼承于java.lang.ClassLoader , 沒有父加載器 , 負(fù)責(zé)加載擴(kuò)展類加載器和應(yīng)用程序類加載器 , 并為它們指定父類加載器

     ClassLoader 類,它是一個(gè)抽象類,其后所有的類加載器都繼承自 ClassLoader (不包括啟動(dòng)類加載器)

      引導(dǎo)類加載器作為頂級(jí)的類加載器, 非java語言實(shí)現(xiàn) , 所以和java中其他類加載器也不存在繼承關(guān)系等

擴(kuò)展類加載器

 Java 語言編寫的,由sun.misc.Launcher$ExtClassLoader 實(shí)現(xiàn). 派生于 ClassLoader 類.

          負(fù)責(zé)從 java.ext.dirs 系統(tǒng)屬性所指定的目錄中加載類庫,或從 JDK 系統(tǒng)安裝目錄jre/lib/ext 子目錄(擴(kuò)展目錄)下加載類庫.如果用戶創(chuàng)建的 jar 放在此目錄下,也會(huì)自動(dòng)由擴(kuò)展類加載器加載

應(yīng)用程序類加載器

     Java 語言編寫的,由 sun.misc.Launcher$AppClassLoader 實(shí)現(xiàn). 派生于 ClassLoader 類.      加載我們自己定義的類,用于加載用戶類路徑(classpath)上所有的類.      該類加載器是程序中默認(rèn)的類加載器.

我們自己寫的類是由應(yīng)用程序類加載器加載的, 類加載器結(jié)構(gòu)示例如下

//獲取應(yīng)用程序類加載器  sun.misc.Launcher$AppClassLoader@18b4aac2
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
System.out.println(classLoader);
//獲得父類加載器 sun.misc.Launcher$ExtClassLoader@74a14482
System.out.println(classLoader.getParent());
//擴(kuò)展類加載器上一級(jí)是引導(dǎo)類加載器,不是java實(shí)現(xiàn),為null
System.out.println(classLoader.getParent().getParent());
//拿到String類的類加載器,結(jié)果為null
//可見,String類為引導(dǎo)類加載器加載
ClassLoader classLoader1 = String.class.getClassLoader();
System.out.println(classLoader1);

另外還有一種叫做用戶自定義類加載器 , 例如 tomcat

4. 雙親委派機(jī)制

什么是雙親委派機(jī)制呢? 

       Java 虛擬機(jī)對(duì) class 文件采用的是按需加載的方式,也就是說當(dāng)需要該類時(shí)才會(huì) 將它的class 文件加載到內(nèi)存中生成 class 對(duì)象.而且加載某個(gè)類的 class 文件 時(shí),Java 虛擬機(jī)采用的是雙親委派模式,即把請(qǐng)求交由父類處理,它是一種任務(wù)委 派模式.

.

      就是說呢, 如果類加載器接收到了加載請(qǐng)求, 并不會(huì)去立即加載這個(gè)類, 而是把請(qǐng)求交給它的上一級(jí)加載器去加載 , 上一級(jí)沒有則繼續(xù)往上找 , 直到頂級(jí)的類加載器(引導(dǎo)類加載器)也無法加載時(shí), 開始往下找 , 如果有一級(jí)加載成功則返回, 最終加載器都無法加載時(shí), 就會(huì)拋出ClassNotFoundException異常

      那么為什么要這樣去做呢? 試想, 我們自己創(chuàng)建一個(gè)java.lang.String類

package java.lang;
public class String {
    public String(){
        System.out.println("自己的String");
    }
}

建立一個(gè)測(cè)試類

public class TestString {
    public static void main(String[] args) {
        new String();
    }
}

        試想 , "自己的String" 這句話會(huì)被輸出嗎 ? 答案肯定是不會(huì)

        因?yàn)榧虞d類的時(shí)候會(huì)先往上走, 此時(shí)走到了引導(dǎo)類加載器, 引導(dǎo)類加載器發(fā)現(xiàn)此類沒有被加載,并且自己可以加載, 那么java.lang.String 就會(huì)被加載了, 此時(shí)就會(huì)直接返回 

        那么雙親委派機(jī)制出現(xiàn)的原因就顯而易見了

      安全,可避免用戶自己編寫的類動(dòng)態(tài)替換 Java 的核心類,如 java.lang.String , 避免全限定命名的類重復(fù)加載(使用了 findLoadClass()判斷當(dāng)前類是否已加載)

5. 類的主動(dòng)/被動(dòng)使用

      JVM 規(guī)定,每個(gè)類或者接口被首次主動(dòng)使用時(shí)才對(duì)其進(jìn)行初始化,有主動(dòng)使用,自然就有被動(dòng)使用.那么什么時(shí)候類被主動(dòng)使用呢?

  • 通過new關(guān)鍵字被導(dǎo)致類的初始化,這是大家經(jīng)常使用的初始化一個(gè)類的方式,他肯定會(huì)導(dǎo)致類的加載并且初始化
  • 訪問類的靜態(tài)變量,包括讀取和更新
  • 訪問類的靜態(tài)方法
  • 對(duì)某個(gè)類進(jìn)行反射操作,會(huì)導(dǎo)致類的初始化
  • 初始化子類會(huì)導(dǎo)致父類的的初始化
  • 執(zhí)行該類的 main 函數(shù)

除了上面的幾種主動(dòng)使用其余就是被動(dòng)使用了

     1.引用該類的靜態(tài)常量,注意是常量,不會(huì)導(dǎo)致初始化,但是也有意外,這里的常量是指已經(jīng)指定字面量的常量,對(duì)于那些需要一些計(jì)算才能得出結(jié)果的常量就會(huì)導(dǎo)致初始化,比如:

public final static int NUMBER = 5 ; //不會(huì)導(dǎo)致類初始化,被動(dòng)使用 public final static int RANDOM = new Random().nextInt() ; //會(huì)導(dǎo)致類的初始化,主動(dòng)使用

     2.構(gòu)造某個(gè)類的數(shù)組時(shí)不會(huì)導(dǎo)致該類的初始化

Student[] students = new Student[10]

      主動(dòng)使用和被動(dòng)使用的區(qū)別在于類是否會(huì)被初始化.

結(jié)語

       到此關(guān)于 jvm 類加載這一章就說完了 , 感謝您的閱讀 , 后續(xù)將會(huì)進(jìn)行 jvm 中運(yùn)行時(shí)數(shù)據(jù)區(qū)的講解 , 感謝您的支持 ,謝謝 !!!

到此這篇關(guān)于詳細(xì)分析JVM類加載機(jī)制的文章就介紹到這了,更多相關(guān)JVM類加載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java程序圖形用戶界面設(shè)計(jì)之標(biāo)簽組件

    Java程序圖形用戶界面設(shè)計(jì)之標(biāo)簽組件

    圖形界面(簡(jiǎn)稱GUI)是指采用圖形方式顯示的計(jì)算機(jī)操作用戶界面。與早期計(jì)算機(jī)使用的命令行界面相比,圖形界面對(duì)于用戶來說在視覺上更易于接受,本篇精講Java語言中關(guān)于圖形用戶界面的標(biāo)簽組件部分
    2022-02-02
  • Java 如何使用@Autowired注解自動(dòng)注入bean

    Java 如何使用@Autowired注解自動(dòng)注入bean

    這篇文章主要介紹了Java 使用@Autowired注解自動(dòng)注入bean的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • JVM如何處理異常深入詳解

    JVM如何處理異常深入詳解

    異常處理的兩大元素:拋出異常、捕獲異常,非正常處理的兩個(gè)方法。下面這篇文章主要給大家介紹了關(guān)于JVM如何處理異常的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2019-01-01
  • Spring-Cloud-Function-Spel?漏洞環(huán)境搭建

    Spring-Cloud-Function-Spel?漏洞環(huán)境搭建

    這篇文章主要介紹了Spring-Cloud-Function-Spel?漏洞復(fù)現(xiàn)及搭建方法,搭建方法也很簡(jiǎn)單,首先需要安裝maven jdk,具體安裝過程跟隨小編一起看看吧
    2022-03-03
  • feign遠(yuǎn)程調(diào)用無法傳遞對(duì)象屬性405的問題

    feign遠(yuǎn)程調(diào)用無法傳遞對(duì)象屬性405的問題

    這篇文章主要介紹了feign遠(yuǎn)程調(diào)用無法傳遞對(duì)象屬性405的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • JAXB命名空間及前綴_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    JAXB命名空間及前綴_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要給大家介紹了關(guān)于JAXB命名空間及前綴的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-08-08
  • 深入理解java.lang.String類的不可變性

    深入理解java.lang.String類的不可變性

    不可變類只是其實(shí)例不能被修改的類。每個(gè)實(shí)例中包含的所有信息都必須在創(chuàng)建該實(shí)例的時(shí)候就提供,并且在對(duì)象的整個(gè)生命周期內(nèi)固定不變,感興趣的可以了解一下
    2021-06-06
  • java學(xué)習(xí):日期的運(yùn)算代碼

    java學(xué)習(xí):日期的運(yùn)算代碼

    java.util.Date下的很多(構(gòu)造)方法,已經(jīng)被標(biāo)識(shí)為"過時(shí)"方法,官方推薦使用Calendar類來處理日期的運(yùn)算,下面是示例:
    2013-02-02
  • Java 獲取服務(wù)器環(huán)境的實(shí)例詳解

    Java 獲取服務(wù)器環(huán)境的實(shí)例詳解

    這篇文章主要介紹了Java 獲取服務(wù)器環(huán)境的實(shí)例詳解的相關(guān)資料,這里提供實(shí)例和輸出結(jié)果,希望能幫助大家理解,需要的朋友可以參考下
    2017-07-07
  • Java中String.split()用法小結(jié)

    Java中String.split()用法小結(jié)

    這篇文章主要介紹了Java中String.split()用法小結(jié)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-07-07

最新評(píng)論