日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

转载---虚拟机类加载机制

發(fā)布時間:2025/7/25 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 转载---虚拟机类加载机制 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?

虛擬機類加載機制?

  虛擬機把描述的類的數(shù)據(jù)從class文件加載到內(nèi)存后,并對數(shù)據(jù)進行校驗,轉(zhuǎn)換解析和初始化,最終形成可以被虛擬機直接使用的Java類型,這就是虛擬機的類加載機制。

?類加載的時機

   類被加載到虛擬機內(nèi)存開始,到卸載出內(nèi)存為止。它的整個生命周期包括:類加載(Loading),驗證(Verification),準備(Preparation),解析(Resolution),初始化(Initialization),使用(Using)和卸載(Unloading)7個階段。其中驗證,準備,解析3個部分統(tǒng)稱為連接(Linking)。

  虛擬機規(guī)范嚴格規(guī)定了有且僅有5種情況必須立即對類進行“初始化”:

  • 遇到new , getstatic , putstatic 或involvestatic這4條字節(jié)碼指令時,如果類沒有進行過初始化,則需要先觸發(fā)其初始化。
  • 使用java.lang.reflect包的方法對類進行反射調(diào)用的時候,如果類沒有進行過初始化,則需要先觸發(fā)其初始化。
  • 當初始化一個類的時候,如果發(fā)現(xiàn)其父類還沒有進行過初始化,則需要先觸發(fā)其父類的初始化。
  • 當虛擬機啟動時,用戶需要指定一個要執(zhí)行的主類(包含main方法的類),虛擬機會先初始化這個類。
  • 當使用JDK1.7的動態(tài)語言支持時,如果java.lang.invoke.MethodHeadle實例,最后的解析結(jié)果REF_getstatic , REF_putstatic , REF_invokestatic的方法句柄,并且這個方法句柄所對應(yīng)的類沒有進行過初始化,則需要先觸發(fā)其初始化。
  • ?類加載的過程

      一、加載

      (1)在加載階段,虛擬機需要完成以下3件事:

  • 通過一個類的全限定名來獲取定義此類的二進制字節(jié)流
  • 將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)
  • 在內(nèi)存中生成一個代表這個類的java.lang.class對象,作為方法區(qū)這個類的各種數(shù)據(jù)的訪問入口
  •   (2)數(shù)組類本身不通過類加載器創(chuàng)建,他是由Java虛擬機直接創(chuàng)建的。

        一個數(shù)組類創(chuàng)建過程遵循以下規(guī)則:

  • 如果數(shù)組的組件類型(Component Type , 指的是數(shù)組去掉一個維度的類型)是引用類型,那就遞歸采用上面介紹的加載過程去加載這個組件類型,數(shù)組將在加載該數(shù)組組件類型的類加載器的類名稱空間上唄標識。
  • 如果數(shù)組的組件類型不是7引用類型,Java虛擬機將會把數(shù)組標記為與引導(dǎo)類加載器關(guān)聯(lián)。
  • 數(shù)組類的可見性與它的組件類型的可見性一致,如果組件類型不是引用類型,需要數(shù)組類的可見性將 默認為public
  • ?

      二、驗證

      驗證是連接階段的第一步,這一階段的目的是為了確保class文件的字節(jié)流包含的信息符合當前虛擬機的要求,并且不會危害虛擬機本省的安全。

      驗證階段大致上會完成以下4個階段的檢驗動作:文件格式驗證、元數(shù)據(jù)驗證、字節(jié)碼驗證、符號引用驗證

      (1 ) 文件格式驗證

  • 第一階段要驗證字節(jié)流是否符合class文件格式的規(guī)范,并且能被當前版本的虛擬機處理。
  • 中油通過了這個階段的驗證后,字節(jié)流才會進入內(nèi)存的方法區(qū)中進行存儲,所以后面的3個驗證階段全部是基于方法區(qū)的存儲結(jié)構(gòu)進行的,不會直接操作字節(jié)碼。
  •  (2 ) 元數(shù)據(jù)驗證

  • 第二階段是對字節(jié)碼描述的信息進行語義分析,以確保其描述的信息符合Java語言規(guī)范的要求。
  • 第二階段的主要目的是對類的元數(shù)據(jù)信息進行語義化驗,保證不存在不符合Java語言規(guī)范的元數(shù)據(jù)信息
  •   (3 ) 字節(jié)碼驗證

  • 督三階段是整個驗證過程中最復(fù)雜的一個階段,主要目的是通過數(shù)據(jù)流和控制流分析,確定程序語義是合法的,符合邏輯的。這個階段將對類的方法體進行校驗分析。保證被校驗類的方法運行時不會做出危害虛擬機安全的時間。
  • 例如:保證任意時刻操作數(shù)棧的數(shù)據(jù)類型與指令代碼序列都能配合工作。保證跳轉(zhuǎn)到方法體以外的字節(jié)碼指令上。
  •   (4 ) 符號引用驗證

  • 最后一個驗證階段的檢驗發(fā)生在虛擬機將符號引用轉(zhuǎn)化為直接引用的時候,這個轉(zhuǎn)化動作將在連接階段的第三階段——解析階段中發(fā)生。符號引用驗證可以看做是對類自身以外的信息進行匹配性校驗。
  • 例如:符號引用中通過字符串描述中的全限定名是否能找到對應(yīng)的類。在特定類中是否存在符合方法的字段描述符以及簡單名稱所描述的方法和字段
  • 符號引用驗證的目的是確定解析動作能正常執(zhí)行,如果無法通過符號引用驗證,那么將會拋出java.lang.IncompatibleClassChangeError異常的子類
  •   

     三、準備

      準備階段是正式為類變量 分配內(nèi)存并設(shè)置類變量初始值的階段,這些變量所使用的內(nèi)存將在方法區(qū)中進行分配。

    ?

      四、解析

      (1)解析階段是虛擬機將常量池內(nèi)的符號引用替換為直接引用的過程。

  • 符號引用(symbolic Reference):符號引用逸一組符號來描述所引用的目標,符號可以是任何形式的字面量,只要使用 時能無歧義地定位到引用目標即可。符號引用與虛擬機實現(xiàn)的內(nèi)存布局無關(guān),引用的目標并不一定已經(jīng)加載到內(nèi)存中。各種虛擬機實現(xiàn)的內(nèi)存布局可以各不相同,但是它們能接受的符號引用必須是一致的,因為符號引用的字面量形式明確定義在Java虛擬機規(guī)范中的class文件格式中。
  • 直接引用(Direct Reference):直接引用可以是直接指向目標的指針。相對偏移量或是一個能間接定位到目標的句柄。直接引用是和虛擬機實現(xiàn)的內(nèi)存布局相關(guān)的,同一個符號引用在不同的虛擬機實例上翻譯出來的直接引用一般不會相同,如果有了直接引用那引用的目標必定已經(jīng)在內(nèi)存中存在。
  •   (2)虛擬機規(guī)范中并未規(guī)定解析階段發(fā)生的具體時間,只要求了執(zhí)行anewarray,checkcast,getfield,getstatic,instanceof,invokedynamic,invokeinterface,invokespecial,invokestatic,invokevirtual,ldc,ldc_w,multianewarray,new,putField和putstatic這16個用于操作符號引用的字節(jié)碼指令之前,先過它們所使用的符號引用進行解析。

      (3)解析動作主要針對類或接口,字段,類方法,接口方法,方法類型,方法句柄和調(diào)用點限定符7類符號引用進行。

      (4)類或接口的解析

        虛擬機完成整個解析的過程需要以下3個步驟

        1)如果c不是一個數(shù)組類型,那虛擬機將會把代表N的全限定名傳遞給D的類加載器去加載這個類C。在加載過程中,由于元數(shù)據(jù)驗證,字節(jié)碼驗證的需要,又可能觸發(fā)其他相關(guān)的類的加載動作。

        2)如果C是一個數(shù)組類型,并且數(shù)組的元素類型為對象,那將會按以上的規(guī)則加載數(shù)組類型。如果N的描述符如前面所假設(shè)的形式,需要加載元素的類型,接著由虛擬機生成一個代表此數(shù)組維度和元素的數(shù)組對象。

        3)如果上面的步驟沒有出現(xiàn)任何異常,那么C在虛擬機中實際上已經(jīng)成為一個有效的類或接口了,但在解析完成之后還要進行符號引用驗證,確認D是否是具備對C的訪問權(quán)限。

      (5)字段解析

      (6)類方法解析

      (7)接口方法解析

    ?

      五、初始化

  • 類初始化階段是類加載過程的最后一步
  • 在準備階段,變量已經(jīng)賦過一次系統(tǒng)要過的初始值,而在初始化階段,則根據(jù)程序員制定的主觀去初始化變量和其他資源,或者可以從另外一個角度來表達:初始化階段是執(zhí)行類構(gòu)造器<cninit>()方法的過程。
  • <clinit>()方法是由編譯器自動收集類中的所有類變量的賦值動作和靜態(tài)語句塊(static{}塊)中的語句合并產(chǎn)生的,編譯器收集的順序是由語句在源文件中出現(xiàn)的順序所決定的,靜態(tài)語句塊只能訪問到定義在靜態(tài)語句塊之前的變量,定義在它之后的變量,在前面的靜態(tài)語句塊可以賦值,但是不能訪問。
  • <clinit>()方法與類的構(gòu)造函數(shù)不同,它不需要顯式地調(diào)用父類構(gòu)造器,虛擬機會保證在子類的<clinit>()方法執(zhí)行之前,父類的<clinit>()方法已經(jīng)執(zhí)行完畢。因此在虛擬機中第一個被執(zhí)行的<clinit>()方法的類肯定有java.lang.object。
  • 由父類的<clinit>()方法先執(zhí)行,也就意味著父類中定義的靜態(tài)語句塊要優(yōu)先于子類的變量賦值操作。
  • <clinit>()方法對于類或接口來說并不是必須的,如果一個類中沒有靜態(tài)語句塊,也沒有對變量的賦值操作,那么編譯器可以不為這個類生成<clinit>()方法
  • 虛擬機會保證一個類的<clinit>()方法在多個線程環(huán)境中正確地加鎖,同步。
  •   

    ?類加載器

      一、類與類加載器

      對于任意一個類,需要由加載它的加載器和這個類本身一同確立其在Java虛擬機中的唯一性,每一個類加載器,都擁有一個獨立的類名稱空間。

      二、雙親委派模型

      (1)從Java虛擬機的角度來講,只存在兩種不同的類加載器:一種是啟動類加載器(Bootstrap Class ClassLoader),這個類加載器使用C++語言實現(xiàn)是Java虛擬機自動的一部分;另一種就是所有其他的類加載器,這些類加載器都由Java語言實現(xiàn),獨立于虛擬機外部,并且全都是繼承自抽象類java.lang.classLoader.

      (2)細分:啟動類加載器(Bootstrap ClassLoader)

            擴展類加載器(Extension ClassLoadert

           ? ? 應(yīng)用程序類加載器(Application ClassLoader)[系統(tǒng)類加載器]

      (3)雙親委派模型工作過程:

        如果一個類加載器收到了類加載器的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,每一個層次的類加載器都是如此,因此所有的加載請求最終都應(yīng)該傳送到頂層類加載器中只有當父類加載器反饋自己無法完成這個類加載請求時,子類加載器才會嘗試自己去加載。

    轉(zhuǎn)載于:https://www.cnblogs.com/jianwei-dai/p/5765779.html

    總結(jié)

    以上是生活随笔為你收集整理的转载---虚拟机类加载机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。