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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

JVM006_类加载的过程

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

類加載

類加載時機

類加載的過程

新術(shù)語

類加載器 簡單的理解為將類轉(zhuǎn)換為二進制流的類或接口。

數(shù)組的元素類型 數(shù)組去掉所有維度的類型。

數(shù)組的組件類型 數(shù)組去掉一個維度的類型。

基本塊 按照控制流拆分的代碼塊。


1. 加載

加載是類加載過程的一個階段。加載階段主要完成三件事情:

  • 根據(jù)類的全限定名,獲取定義此類的二進制字節(jié)流。
  • 將這個二進制字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)換為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)。
  • 在內(nèi)存中生成一個代表該類的java.lang.Class對象,作為訪問方法區(qū)中該類各種數(shù)據(jù)的外部接口。
  • 在上述的1中,沒有限定此類的格式,所以可以是一個class文件,可以是一個jar包,也可以是運行時生成等等。我們可以通過重寫一個類加載器的findclass()方法或者loadClass方法來自定義字節(jié)流的獲取方法。

    數(shù)組與類加載器

    數(shù)組類本身是由JVM在內(nèi)存中直接構(gòu)造的,但是又與類加載器緊密聯(lián)系,其遵循規(guī)則如下:

  • 如果數(shù)組的組件類型是一個引用類型,那么會遞歸的使用加載過程去加載該組件類型,數(shù)組將被標識在加載該組件類型的類加載器的類名稱空間上。

  • 若組件類型是基本類型,JVM會將該數(shù)組標記為與BootStrapClassLoader關(guān)聯(lián)

  • 數(shù)組類的可訪問性與其組件類型的可訪問性一致。

  • 2. 驗證

    驗證是連接的第一步,器目的是確保Class文件的字節(jié)流中包含的信息完全符合《JVM規(guī)范》中的全部約束條件,保證這些信息在運行時不會威脅到JVM的安全。其大致可分為四個階段:文件格式驗證,元數(shù)據(jù)驗證,字節(jié)碼驗證和符號引用驗證。

    文件格式驗證

    這一階段要驗證字節(jié)流是否符合Class文件格式的規(guī)范,以保證輸入的字節(jié)流能夠正確的解析并存儲到方法區(qū)內(nèi)。格式上要符合一個Java類型信息的要求。只有文件格式驗證通過后,才能將字節(jié)流中的信息存儲到方法區(qū)中,所有后面的是三個驗證,都是基于方法區(qū)的存儲結(jié)構(gòu)進行的,而不是字節(jié)流。

    元數(shù)據(jù)驗證

    這個階段要求對字節(jié)碼的描述信息進行語義分析,也就是保證其描述的信息符合《Java語言規(guī)范》的要求。

    字節(jié)碼驗證

    該驗證的目的是通過數(shù)據(jù)流分析和控制流分析,確定程序語義的合法性、合邏輯性。在元數(shù)據(jù)驗證通過后,該階段對類的方法體(也就是Class文件中的Code屬性)進行校驗分析,保證類的方法不會在運行時危害到JVM。

    在JDK6后,將盡可能多的校驗輔助措施挪到j(luò)avac編譯器中,具體的做法是在Code屬性中增加了一個StackMapTable屬性,該屬性描述了方法體所有的基本塊開始時本地變量和操作棧應(yīng)有的狀態(tài)。在字節(jié)碼驗證時,只需要檢查StackMapTable中記錄是否合法即可,而不用根據(jù)程序推導(dǎo)這些狀態(tài)的合法性。

    符號引用驗證

    該階段發(fā)生在JVM將符號引用轉(zhuǎn)為直接引用的時候,其在連接的第三階段解析階段才發(fā)生。是對類自身以外的各類信息進行匹配性校驗,比如說該類是否缺少或禁止訪問它依賴的某些額外部類等,若無法通過驗證,會排除java.lang.IncompatibleClassChangeError的子類異常(java.lang.NoSuchFieldError等)。

    3. 準備

    準備階段是正式為被static修飾的變量(類變量)分配內(nèi)存并設(shè)置初始值的階段。

    特別注意:

    • 此階段的內(nèi)存分配,僅僅包括類變量,不包括實例變量。

    • 若類變量同時被final修飾(也就是通常說的常量),那么其賦值不會是基本類型的零值,而是指定的值。

      例如public staitc final int INIT_VALUE=99,那么在準備階段INIT_VALUE會被賦值為99,而不是0,這是因為被static final同時修飾是,在javac編譯時,字段屬性表中會有一個ConstantValue屬性,在準備階段,該變量值就會被初始化為ConstantValue屬性所指定的初始值。

    基本數(shù)據(jù)的零值

    數(shù)據(jù)類型零值
    int0
    long0L
    short(short)0
    char‘\u0000’
    byte(byte)0
    booleanfalse
    float0.0f
    double0.0d
    referencenull

    4. 解析

    解析是JVM將符號引用轉(zhuǎn)換為直接引用的過程。

    符號引用 以一組符號來描述所引用的目標,符號可以是任何形式的字面量,只要在使用時能夠無歧義的定義到目標即可。符號引用與JVM的內(nèi)存布局無關(guān)。

    直接引用 是可以直接指向目標的指針、相對偏移量或者一個能夠間接定位到目標的句柄。其與JVM內(nèi)存布局直接相關(guān)。

    句柄 是由系統(tǒng)所管理的引用標識,該標識可以被系統(tǒng)重新定位到一個內(nèi)存地址上。

    解析動作主要針對類或結(jié)構(gòu)、字段、類方法、接口方法、方法類型、方法句柄和調(diào)用點限定符這七類符號醫(yī)用進行,其對應(yīng)著8種常量類型。

    4.1 類或者接口的解析

    假設(shè)當前的類為D,要將其中未解析過的符號引用N解析為一個類或者接口C的直接引用。大概過程如下:

  • 若C不是一個數(shù)組,那么JVM會將代表N的全限定類名交個D的類加載器,由其去加載這個類C。若在C的加載過程中出現(xiàn)異常,那么解析過程宣告失敗。
  • 若C是一個數(shù)組,并且數(shù)組的元素類型是對象,那么會按照上一步的步驟去加載元素類型,再由JVM生成數(shù)組對象。
  • 若1、2都沒問題,則檢查D對C的訪問權(quán)限。若沒有權(quán)限則會拋出java.lang.IllegalAccessError。
  • 4.2 字段解析

    若要對一個沒有經(jīng)過解析的字段進行解析,首先我們需要看字段表內(nèi)的class_index項中的CONSTANT_class_info符號引用進行解析(參考類文件結(jié)構(gòu)),也就是對字段對應(yīng)的類或者接口的引用的解析。

    假設(shè)字段對應(yīng)的類或接口為C,那么在解析類或接口成功后,會根據(jù)《JVM規(guī)范》對字段進行搜索:

  • 若C本身包含的簡單名稱和字段描述符都與目標相匹配的字段,則返回這個字段的直接引用,搜索結(jié)束。
  • 否則,若C實現(xiàn)了接口,那么將會按照繼承關(guān)系從下向上遞歸搜索各個接口及父接口,若接口中包含了簡單名稱和字段描述符都與目標相匹配的字段,則返回該字段的直接引用,搜索結(jié)束。
  • 否則,若C不是java.lang.Object的話,就會按照繼承關(guān)系從下向上遞歸搜索其父類,若在父類中包含了簡單名稱和字段描述符與之相匹配的字段,則返回該字段的直接引用,搜索結(jié)束。
  • 否則查找失敗,拋出java.lang.NoSuchFieldError異常。
  • 若查找過程成功返回了引用,則進行訪問權(quán)限驗證,若無權(quán)限拋出java.lang.IllegalAccessError異常。
  • 4.3 方法解析

    方法解析的第一步也是對方法表內(nèi)的class_index項中的CONSTANT_class_info符號引用進行解析(參考類文件結(jié)構(gòu))。若解析成功則會按照如下的規(guī)則來搜尋對應(yīng)的方法。

  • Class文件格式中類的方法和接口的方法的符號引用時分開存儲的,所以若類的方法表中發(fā)現(xiàn)class_index對應(yīng)的是一個接口的,則拋出java.lang.IncompatibleChangeError。
  • 若1通過,若類C中有簡單名稱和描述符都與目標匹配的,則返回這個方法的直接引用,搜索結(jié)束。
  • 否則,在類C的父類中遞歸查找簡單名稱和描述符與目標都匹配的方法,若有則返回這個方法的直接引用,搜索結(jié)束。
  • 否則,在類C的接口列表及他們的父接口中遞歸查詢簡單名稱和描述符與目標都匹配的方法,若有,則表示C是一個抽象類,搜索結(jié)束,拋出java.lang.AbstractMethodError。
  • 否則,查找失敗,拋出java.lang.NoSuchMethodError。
  • 若查找過程成功返回了引用,則進行訪問權(quán)限驗證,若無權(quán)限拋出java.lang.IllegalAccessError異常。
  • 4.4 接口方法解析

    基本同方法解析。若接口解析成功,接下來的方法搜索規(guī)則如下:

  • 若方法表中class_index對應(yīng)的是一個類,java.lang.IncompatibleChangeError排除異常。
  • 否則在C中查找是否有簡單名稱和描述符都與目標相配的方法,則返回該方法的直接引用,搜索結(jié)束。
  • 否則,在接口C的父類中遞歸查找,直到j(luò)ava.lang.Object,有簡單名稱和描述符都與目標相配的方法,則返回該方法的直接引用,搜索結(jié)束。
  • 對于3,由于接口運行多繼承,所以存在在多個接口中都有簡單名稱和描述符都與目標相配的情況,那么會從這些方法中返回一個,并結(jié)束查找。
  • 否則,查找失敗,拋出java.lang.NoSuchMethodError。
  • 若查找過程成功返回了引用,則進行訪問權(quán)限驗證,若無權(quán)限拋出java.lang.IllegalAccessError異常。(JDK9的影響)
  • 5. 初始化

    類初始化是類加載過程的最后一個階段。在這個階段JVM才真正開始執(zhí)行類中編寫的程序代碼,將主導(dǎo)權(quán)交給程序。在準備階段,已經(jīng)對類變量賦了零值,在這一階段,將會根據(jù)程序編碼去初始化類變量和其它資源。也可以說初始化就是執(zhí)行類構(gòu)造器()方法的過程。

    接下來我們對<clinit>()方法做一些說明。

    • <clinit>()方法是由javac編譯器自動生成的,是由編譯器自動收集類中的所有類變量的賦值動作和靜態(tài)語句塊(static{})中的語句合并產(chǎn)生的,編譯器收集的順序是由語句在源文件中出現(xiàn)的順序覺得的,靜態(tài)語句塊中只能訪問到在靜態(tài)語句塊之前的變量,定義在其之后的變量,在該語句塊中只能賦值不能訪問。
    • <clinit>()方法與<init>()方法(類的構(gòu)造函數(shù))不同,它不需要顯示的調(diào)用父類構(gòu)造器,JVM會保證在子類的<clinit>()執(zhí)行前,父類的<clinit>()已經(jīng)執(zhí)行完畢。可以推論出,JVM中第一個被執(zhí)行的<clinit>()方法是java.lang.Object的。
    • 由于父類的<clinit>()先執(zhí)行,所以父類的靜態(tài)語句塊要優(yōu)先于子類的變量賦值操作。
    • <clinit>()對于接口來說是非必要的。
    • 接口中不能使用靜態(tài)代碼塊,但是可能存在類變量的賦值操作,因而接口也會生成<clinit>()方法。但是當接口的<clinit>()方法執(zhí)行時,不要求父接口的<clinit>()方法先執(zhí)行,只有當父類中定義的變量被使用時,父接口才會被初始化。此外,接口的實現(xiàn)類在初始化時也不會執(zhí)行接口的<clinit>()方法。
    • JVM必須保證一個類的<clinit>()方法在多線程環(huán)境下被正確的加鎖同步。若一個類的<clinit>()方法中有耗時很長的操作,那就可能造成阻塞。

    類加載器

    對于任意一個類,都必須由加載它的類加載器和這個類本身一起確立其在JVM中的唯一性。

    雙親委派模式

    從虛擬機的視角類加載器可以分為:

  • BootStrapClassLoader啟動類加載器,用C++實現(xiàn),是JVM的一部分。
  • 其他類加載器,用Java實現(xiàn),都繼承了抽象類java.lang.ClassLoader,獨立存在于JVM之外。
  • 從使用這角度可分為:

  • BootStrapClassloader

    負責加載在<JAVA_HOME>\lib目錄,或者被-Xbootclasspath參數(shù)所指定的路徑中存放的,并且是能夠被JVM所識別的類庫加載到虛擬機內(nèi)存中。

  • Extension Class Loader 這個類是在sum.mis.Launcher$ExtClassLoader中以Java代碼實現(xiàn)的。它負責加載<JAVA_HOME>\ext\目錄中,或者被java.ext.dirs系統(tǒng)變量所指定的路徑中的所有類庫。

  • Application Class Loaser這個類由``sum.mis.Launcher$AppClassLoader`來實現(xiàn),有時也被稱為“系統(tǒng)類加載器”,它用來加載用戶類路徑上所有的類庫。

  • JDK9之前的Java應(yīng)用都是由這三類加載器來相互配合完成加載。通常這些類加載器按照下圖的協(xié)作關(guān)系來完成加載:

    [外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ztTqTNW1-1617897204791)(https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg4.mukewang.com%2F5bdf01aa0001a43210380303.jpg&refer=http%3A%2F%2Fimg4.mukewang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1620482748&t=d3df08dd58dfb0a1299f9f0207afff4c)]

    這樣的模型被稱為雙親委派模型,其工作過程如下:

    若一個類加載器收到了類加載請求,它首先不會自己去加載,而是將這個請求委托給父類加載器去完成,每一層次的類加載器都是如此。因此所有的加載請求最終都應(yīng)該傳送到最頂層的BootStrapClassloader ,只有當父加載器反饋自己無法完成這個加載請求(及在它的搜索范圍類沒有找到所需的類),子需求才會去嘗試自己完成加載。

    注意:雙親委派中的父加載器,不是繼承關(guān)系中的父子關(guān)系,而是通過組合關(guān)系來復(fù)用父加載器的代碼。

    破壞雙親委派

    在上一點中我們提到通常情況下,加載是按照雙親委派模型執(zhí)行,意味著存在這其它方法,也就是雙親委派模型被破壞。按歷史反正可以分為下面三種情況:

    第一次:

    由于雙親委派模型是JDK1.2引入的,ClassLoader是在第一個版本就存在了的,并且加載的核心代碼在loadClass中(可參考《JVM》P284),所以為了兼容用戶已經(jīng)自定義類加載器的情況,雙親委派在實現(xiàn)中做出了妥協(xié),在loadClass方法中加了一個protected修飾的findClass方法,并引導(dǎo)用戶使用findClass。

    第二次:

    第二次破壞是基于雙親委派的模型自身的缺陷,雙親委派很好的解決了基礎(chǔ)類型一致性的問題,但是對于基礎(chǔ)類型需要回調(diào)用戶的代碼,雙親委派無能為力。這個時候引入線程上下文類加載器。!待深入研究

    第三次:

    這次破壞基于對代碼熱替換,模塊熱部署的追求。例如OSGi。!待深入研究


    參考資料:

    《深入理解Java虛擬機》

    Tomcat類加載器破壞雙親委派

    從JDBC看“破壞”雙親委派模型

    真正理解線程上下文類加載器

    服務(wù)發(fā)現(xiàn)機制


    ?

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

    總結(jié)

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

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

    主站蜘蛛池模板: 中文字幕免费视频观看 | 狼色网 | 国产精品日本 | 久久精品视频无码 | 欧美日韩一级片在线观看 | 大黑人交xxx极品hd | 国产精品久久婷婷六月丁香 | 久久综合激情 | 黄色动漫免费在线观看 | 久久尤物 | 丰满熟妇被猛烈进入高清片 | 人人草人人澡 | 性欧美在线观看 | 狠狠干干 | 国产精品黄视频 | 91美女精品| 99热精品在线观看 | 久久久无码人妻精品一区 | yy1111111| 男女无遮挡免费视频 | www.一起操| 亚洲黄色片视频 | 亚洲每日在线 | 久久人人爽人人爽人人片亚洲 | 国产h片在线观看 | 色婷婷久久综合中文久久蜜桃av | 91叼嘿视频| 免费在线一区二区三区 | www.毛片| 国产高清黄色 | 亚洲欧美自拍另类 | 亚洲AV成人无码久久精品巨臀 | 视频免费在线 | 国产精选一区二区 | 人妻少妇久久中文字幕 | 奇米在线视频 | 伊人蕉| 久草www | 亚洲成人伦理 | 视色在线 | 飘花影院伦理片 | 亚av | 国产成人精品777777 | 日本寂寞少妇 | 久久乐av | 精品国模| 聚色屋 | 视频在线观看99 | 成人免费黄色大片v266 | 亚洲乱码日产精品bd在线观看 | 成人午夜sm精品久久久久久久 | 国产综合影院 | 亚色在线 | 在线免费精品视频 | 国产精品无码一区二区桃花视频 | 老牛嫩草二区三区观影体验 | 国产新婚疯狂做爰视频 | 久草福利资源在线观看 | 国产情侣自拍av | 一级做a爱片久久 | 国产精品又黄又爽又色无遮挡 | 日韩精品一区二区三区网站 | 麻豆视频在线观看免费网站 | 无码一区二区三区免费视频 | 一级女性全黄久久生活片免费 | av有声小说一区二区三区 | 免费欧美 | 国产女人高潮的av毛片 | 高清日韩欧美 | av先锋资源 | 黄色综合网 | 国产成人一区 | 亚洲精品911| 欧美国产日韩一区二区三区 | 国产精品久久99 | 四虎午夜影院 | 天堂在线资源网 | 欧美中文字幕在线观看 | 欧美综合激情网 | 五月婷婷六月丁香综合 | www.黄色网| 91精产国品一二三区在线观看 | 成人久久一区 | 久久中文字幕网 | 亚洲第一二三四区 | www.色午夜 | 污污动态图 | 亚洲一级视频在线观看 | 乱色欧美 | 欧美aaa级 | 性免费视频 | 免费一级欧美片在线播放 | 国产精品视频在线免费观看 | 欧类av怡春院 | 老外一级片 | 巨胸喷奶水www久久久免费动漫 | 国产精品一区二区自拍 | 欧美大片一区二区三区 | 热久久中文字幕 |