<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          深入理解Java虛擬機(jī):JVM類加載機(jī)制

          共 3766字,需瀏覽 8分鐘

           ·

          2021-08-16 10:51

          作者:老實(shí)巴交

          來源:SegmentFault 思否社區(qū)


          類加載


          首先我們需要明確,JVM是動態(tài)加載class類的,而不是一次性加載程序中所有的class文件(延遲加載機(jī)制)。當(dāng)我們需要這個類的時候,比如說程序在運(yùn)行過程中classA需要調(diào)用另一個classB的方法,但classB沒有被加載,這時候就需要通過類加載機(jī)制動態(tài)加載classB到內(nèi)存中,只有當(dāng)classB被加載到內(nèi)存中,它的方法才能被classA調(diào)用。

          類加載:通過加載,連接和初始化三個過程將class文件中的信息加載到JVM內(nèi)存中。

          1、加載:

          1、通過類的全限定性類名獲取該類的二進(jìn)制流;

          怎么找呢?在系統(tǒng)類和指定的類路徑中尋找,如果是class文件的根目錄,就直接查看是否有對應(yīng)的子目錄及文件,如果是jar文件,則現(xiàn)在內(nèi)存中解壓該文件,再查看有無對應(yīng)的類。對于數(shù)組類來說,它并沒有對應(yīng)的字節(jié)流,而是由 Java 虛擬機(jī)直接生成的,但是數(shù)組類的元素類型是類加載器加載的。對于其他的類來說,Java 虛擬機(jī)則需要借助類加載器來完成查找字節(jié)流的過程。

          2、將該二進(jìn)制流的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)為方法區(qū)的運(yùn)行時數(shù)據(jù)結(jié)構(gòu);

          3、在堆中為該類生成一個java.lang.Class對象,作為方法區(qū)這個類的各種數(shù)據(jù)結(jié)構(gòu)訪問入口

          而類加載器在這個過程中扮演了重要的角色,類加載器主要有兩個作用

          一:用來動態(tài)地加載class類,將class的字節(jié)碼形式轉(zhuǎn)換為內(nèi)存形式的class對象。

          為什么是動態(tài)的呢?這里就涉及到JVM的延遲加載機(jī)制,JVM并不是一次性加載程序中的所有類的,而是按需加載,也就是當(dāng)一個程序中遇到不認(rèn)識的新類的時候,調(diào)用ClassLoader來加載這個類,加載完成后就會將Class對象存在ClassLoader中,下次就不需要加載了。一個寫好的Java程序可能有很多類,這些類呢,有很多方法,在程序運(yùn)行時候經(jīng)常需要從一個class中調(diào)用另一個class中的方法,但是系統(tǒng)啟動的時候不會一次性加載程序中的所有class文件,而是根據(jù)需要通過JVM的類加載機(jī)制來動態(tài)地加載某個class文件到內(nèi)存中,只有當(dāng)class文件被加載到內(nèi)存中,才能被其他class引用,所以classLoader是用來動態(tài)加載class文件到內(nèi)存中的。

          比較形象的例子就是調(diào)用某個類的靜態(tài)方法,那么需要加載這個類(因?yàn)殪o態(tài)方法在類被創(chuàng)建出來之后就有了),但并不需要加載這個類的實(shí)例,而實(shí)例是在被程序調(diào)用的時候才會被加載。

          二:它是類的命名空間,起到了類隔離的作用。在同一個ClassLoader里面加載的類名是唯一不可重復(fù)的,不同類加載器中的同名類是兩個不同的類。類的唯一性是由類加載器實(shí)例以及類的全名一同確定的。即便是同一串字節(jié)流,經(jīng)由不同的類加載器加載,也會得到兩個不同的類。在大型應(yīng)用中,我們往往借助這一特性,來運(yùn)行同一個類的不同版本。

          類加載器:

          啟動類加載器:在Java 8 時,主要加載java的基礎(chǔ)類,也就是JAVA_HOME/jre/lib/rt.jar下的所有class,Java 9以后它負(fù)責(zé)加載啟動時的基礎(chǔ)模塊類(如 Java.base; java.manager;java.xml)。它是通過C++實(shí)現(xiàn)的,并不存在于JVM體系中,所以輸出是null。

          在JVM啟動時,通過Bootstrap ClassLoader加載rt.jar,并初始化sun.misc.Launcher從而創(chuàng)建Extension ClassLoader和Application ClassLoader的實(shí)例。

          擴(kuò)展類加載器 它主要加載\lib\ext或者java.ext.dirs系統(tǒng)變量指定的路徑中的所有類庫;加載一些拓展的系統(tǒng)類,比如XML、加密、壓縮相關(guān)的功能類。

          它由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn);向上繼承自URLClassLoader, URLClassLoader向上繼承自SecueClassLoader,SecueClassLoade繼承自ClassLoader。

          在java 9以后替換為平臺類加載器,加載平臺相關(guān)的模塊,比如比如java.scripting、java.compiler、 java.corba。

          應(yīng)用類加載器 在Java 8 中主要加載classpath所有的jar包和類,Java 9 中用于加載應(yīng)用級別的模塊,入jdk.compiler; jdk.jartool; jdk.jshell。

          它由sun.misc.Launcher$AppClassLoader實(shí)現(xiàn)。

          如果應(yīng)用程序中沒有定義自己的加載器,則該加載器也就是默認(rèn)的類加載器。該加載器可以通過java.lang.ClassLoader.getSystemClassLoader獲取。

          雙親委派機(jī)制

          先自底向上判斷該類是否被加載過,若已經(jīng)被加載,直接返回

          若未被加載,則自頂向上嘗試加載類,當(dāng)父類沒有所需的類,無法加載的時候,子加載器嘗試去完成加載,如果JVM內(nèi)置的類加載器無法加載,則有自定義加載器進(jìn)行加載

          具體:當(dāng)一個ClassLoader實(shí)例需要加載某個類時,它會試圖親自搜索某個類之前,先把這個任務(wù)委托給它的父類加載器,這個過程是由上至下依次檢查的,首先由最頂層的類加載器Bootstrap ClassLoader試圖加載,如果沒加載到,則把任務(wù)轉(zhuǎn)交給Extension ClassLoader試圖加載,如果也沒加載到,則轉(zhuǎn)交給App ClassLoader 進(jìn)行加載,如果它也沒有加載得到的話,則返回給委托的發(fā)起者,由它到指定的文件系統(tǒng)或網(wǎng)絡(luò)等URL中加載該類。如果它們都沒有加載到這個類時,則拋出ClassNotFoundException異常。否則將這個找到的類生成一個類的定義,并將它加載到內(nèi)存當(dāng)中,并進(jìn)行后面的步驟,最后返回這個類在內(nèi)存中的Class實(shí)例對象。

          Parents Delegation Model:雙親委派模型,簡單可以理解為優(yōu)先級和共享兩個關(guān)鍵詞,為了防止Java核心API被替換,根加載器優(yōu)先加載,如果沒有,那么自頂向下加載。當(dāng)多個子 ClassLoader 共享同一個 parent 時,那么這個 parent 里面包含的類可以認(rèn)為是所有子 ClassLoader 共享的。這也是為什么 BootstrapClassLoader 被所有的類加載器視為祖先加載器,JVM 核心類庫自然應(yīng)該被共享。

          2、連接

          1驗(yàn)證,主要是為了確保class文件的字節(jié)流中包含的信息符合Java虛擬機(jī)規(guī)范,保證這些信息被當(dāng)作代碼的時候不會危害虛擬機(jī)自身的安全。

          主要是格式驗(yàn)證,元數(shù)據(jù)驗(yàn)證(是否符合Java語言規(guī)),字節(jié)碼驗(yàn)證(確定程序語義合法,符合邏輯),符號驗(yàn)證(確保下一步的解析能正常執(zhí)行)。它很重要,但不是必須執(zhí)行的。

          2準(zhǔn)備為靜態(tài)變量在方法區(qū)分配內(nèi)存,并設(shè)置初始默認(rèn)值。僅僅是類變量(即靜態(tài)變量),而不包括實(shí)例變量,實(shí)例變量是在對象實(shí)例化后隨著對象一塊兒分配到Java堆中。而類變量在JDK7之前存放在方法區(qū)中,而7以后隨著Class對象存放在Java堆中。(這里可能會考默認(rèn)值,int 0,long 0等等)。

          3虛擬機(jī)將常量池內(nèi)的符號引用替換成直接引用的過程。解析動作主要針對類或接口、字段、類方法、接口方法、方法類型、方法句柄和調(diào)用限定符 7 類符號引用進(jìn)行。符號引用就是一組符號來描述目標(biāo),可以是任何字面量。直接引用就是直接指向目標(biāo)的指針、相對偏移量或一個間接定位到目標(biāo)的句柄。更多的問多態(tài)

          注意:Java 虛擬機(jī)規(guī)范并沒有要求在鏈接過程中完成解析。它僅規(guī)定了:如果某些字節(jié)碼使用了符號引用,那么在執(zhí)行這些字節(jié)碼之前,需要完成對這些符號引用的解析。

          3、初始化

          是為標(biāo)記為常量值的字段賦值,以及執(zhí)行 < clinit > 方法的過程。

          當(dāng)有繼承關(guān)系時,先初始化父類再初始化子類,所以創(chuàng)建一個子類時其實(shí)內(nèi)存中存在兩個對象實(shí)例。如果要初始化一個靜態(tài)字段,我們可以在聲明時直接賦值,也可以在靜態(tài)代碼塊中對其賦值。如果直接賦值的靜態(tài)字段被 final 所修飾,并且它的類型是基本類型或字符串時,那么該字段便會被 Java 編譯器標(biāo)記成常量值(ConstantValue),其初始化直接由 Java 虛擬機(jī)完成。除此之外的直接賦值操作,以及所有靜態(tài)代碼塊中的代碼,則會被 Java 編譯器置于同一方法中,并把它命名為 < clinit >。Java 虛擬機(jī)會通過加鎖來確保類的 < clinit > 方法僅被執(zhí)行一次,這個特性被用來實(shí)現(xiàn)單例的延遲初始化。



          點(diǎn)擊左下角閱讀原文,到 SegmentFault 思否社區(qū) 和文章作者展開更多互動和交流,掃描下方”二維碼“或在“公眾號后臺回復(fù)“ 入群 ”即可加入我們的技術(shù)交流群,收獲更多的技術(shù)文章~

          - END -


          瀏覽 43
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  丁香五月婷操 | 99热.con | 在线观看的A片 | 欧美婬乱片A片AAA毛片地址 | 大香蕉伊思人在线 |