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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

深入理解Java虚拟机(类加载机制)

發(fā)布時間:2025/4/16 java 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解Java虚拟机(类加载机制) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章首發(fā)于微信公眾號:BaronTalk

上一篇文章我們介紹了「類文件結構」,這一篇我們來看看虛擬機是如何加載類的。

我們的源代碼經(jīng)過編譯器編譯成字節(jié)碼之后,最終都需要加載到虛擬機之后才能運行。虛擬機把描述類的數(shù)據(jù)從 Class 文件加載到內(nèi)存,并對數(shù)據(jù)進行校驗、轉換解析和初始化,最終形成可以被虛擬機直接使用的 Java 類型,這就是虛擬機的類加載機制

與編譯時需要進行連接工作的語言不同,Java 語言中類的加載、連接和初始化都是在程序運行期間完成的,這種策略雖然會讓類加載時增加一些性能開銷,但是會為 Java 應用程序提供高度的靈活性,Java 里天生可動態(tài)擴展的語言特性就是依賴運行期間動態(tài)加載和動態(tài)連接的特點實現(xiàn)的。

例如,一個面向接口的應用程序,可以等到運行時再指定實際的實現(xiàn)類;用戶可以通過 Java 預定義的和自定義的類加載器,讓一個本地的應用程序運行從網(wǎng)絡上或其它地方加載一個二進制流作為程序代碼的一部分。

一. 類加載時機

類從被虛擬機從加載到卸載,整個生命周期包含:加載(Loading)、驗證(Verification)、準備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸載(Unloading)7 個階段。其中驗證、準備、解析 3 個部分統(tǒng)稱為連接(Linking)。這 7 個階段的發(fā)生順序如下圖:

?

上圖中加載、驗證、準備、初始化和卸載 5 個階段的順序是確定的,類的加載過程必須按照這種順序按部就班的開始「注意,這里說的是按部就班的開始,并不要求前一階段執(zhí)行完才能進入下一階段」,而解析階段則不一定:它在某些情況下可以在初始化階段之后再開始,這是為了支持 Java 的動態(tài)綁定。

虛擬機規(guī)范中對于什么時候開始類加載過程的第一節(jié)點「加載」并沒有強制約束。但是對于「初始化」階段,虛擬機則是嚴格規(guī)定了有且只有以下 5 種情況,如果類沒有進行初始化,則必須立即對類進行「初始化」(加載、驗證、準備自然需要在此之前開始):

  • 遇到 new、getstatic、putstatic 或 invokestatic 這 4 條字節(jié)碼指令;
  • 使用 java.lang.reflect 包的方法對類進行反射調(diào)用的時候;
  • 當初始化一個類的時候,發(fā)現(xiàn)其父類還沒有進行初始化的時候,需要先觸發(fā)其父類的初始化;
  • 當虛擬機啟動時,用戶需要指定一個要執(zhí)行的主類,虛擬機會先初始化這個類;
  • 當使用 JDK 1.7 的動態(tài)語言支持時,如果一個 java.lang.invoke.MethodHandle 實例最后的解析結果 REF_getStatic、REF_putStatic、REF_invokeStatic 的方法句柄,并且這個方法句柄所對應的類沒有初始化。
  • 「有且只有」以上 5 種場景會觸發(fā)類的初始化,這 5 種場景中的行為稱為對一個類的主動引用。除此之外,所有引用類的方式都不會觸發(fā)初始化,稱為被動引用。比如如下幾種場景就是被動引用:

  • 通過子類引用父類的靜態(tài)字段,不會導致子類的初始化;
  • 通過數(shù)組定義來引用類,不會觸發(fā)此類的初始化;
  • 常量在編譯階段會存入調(diào)用類的常量池中,本質(zhì)上并沒有直接引用到定義常量的類,因此不會觸發(fā)定義常量的類的初始化;
  • 二. 類加載過程

    加載

    這里的「加載」是指「類加載」過程的一個階段。在加載階段,虛擬機需要完成以下 3 件事:

  • 通過一個類的全限定名來獲取定義此類的二進制字節(jié)流;
  • 將這個字節(jié)流所代表的靜態(tài)存儲結構轉化為方法區(qū)的運行時數(shù)據(jù)結構;
  • 在內(nèi)存中生成一個代表這個類的 java.lang.Class 對象,作為方法區(qū)這個類的各種數(shù)據(jù)的訪問入口。
  • 驗證

    驗證是連接階段的第一步,這一階段的目的是為了確保 Class 文件的字節(jié)流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全。驗證階段大致上會完成下面 4 個階段的檢驗動作:

  • 文件格式驗證:第一階段要驗證字節(jié)流是否符合 Class 文件格式的規(guī)范,并且能夠被當前版本的虛擬機處理。驗證點主要包括:是否以魔數(shù) 0xCAFEBABE 開頭;主、次版本號是否在當前虛擬機處理范圍之內(nèi);常量池的常量中是否有不被支持的常量類型;Class 文件中各個部分及文件本身是否有被刪除的或者附加的其它信息等等。

  • 元數(shù)據(jù)驗證:第二階段是對字節(jié)碼描述的信息進行語義分析,以保證其描述的信息符合 Java 語言規(guī)范的要求,這個階段的驗證點包括:這個類是否有父類;這個類的父類是否繼承了不允許被繼承的類;如果這個類不是抽象類,是否實現(xiàn)了其父類或者接口之中要求實現(xiàn)的所有方法;類中的字段、方法是否與父類產(chǎn)生矛盾等等。

  • 字節(jié)碼驗證:第三階段是整個驗證過程中最復雜的一個階段,主要目的是通過數(shù)據(jù)流和控制流分析,確定程序語義是合法的、符合邏輯的。

  • 符號引用驗證:最后一個階段的校驗發(fā)生在虛擬機將符號引用轉化為直接引用的時候,這個轉化動作將在連接的第三階段--解析階段中發(fā)生。符號引用驗證可以看做是對類自身以外(常量池中的各種符號引用)的形象進行匹配性校驗。

  • 準備

    準備階段是正式為類變量分配內(nèi)存并設置類變量初始值的階段,這些變量所使用的內(nèi)存都將在方法區(qū)進行分配。這個階段中有兩個容易產(chǎn)生混淆的概念需要強調(diào)下:

    • 首先,這時候進行內(nèi)存分配的僅包括類變量(被 static 修飾的變量),而不包括實例變量,實例變量將會在對象實例化時隨著對象一起分配在 Java 堆中;

    • 其次這里所說的初始值「通常情況」下是數(shù)據(jù)類型的零值。假設一個類變量的定義為public static int value = 123;?那么變量?value?在準備階段過后的初始值為 0 而不是 123,因為這個時候尚未執(zhí)行任何 Java 方法,而把 value 賦值為 123 的 putstatic 指令是程序被編譯之后,存放于類構造器?() 方法之中,所以把 value 賦值為 123 的動作將在初始化階段才會執(zhí)行。

    這里提到,在「通常情況」下初始值是零值,那相對的會有一些「特殊情況」:如果類字段的字段屬性表中存在 ConstantsValue 屬性,那在準備階段變量 value 就會被初始化為 ConstantValue 屬性所指的值。假設上面的類變量 value 的定義變?yōu)?span id="ozvdkddzhkzd" class="Apple-converted-space">?public static final int value = 123;,編譯時 JavaC 將會為 value 生成 ConstantValue 屬性,在準備階段虛擬機就會根據(jù) ConstantValue 的設置將 value 賦值為 123。

    解析

    解析階段是虛擬機將常量池內(nèi)的符號引用替換為直接引用的過程。前面提到過很多次符號引用和直接引用,那么到底什么是符號引用和直接引用呢?

    • 符號引用(Symbolic Reference):符號引用以一組符號來描述所引用的目標,符號可以上任何形式的字面量,只要使用時能無歧義地定位到目標即可。

    • 直接引用(Direct Reference):直接引用可以是直接指向目標的指針、相對偏移量或是一個能間接定位到目標的句柄。

    初始化

    類初始化階段是類加載過程中的最后一步,前面的類加載過程中,除了在加載階段用戶應用程序可以通過自定義類加載器參與之外,其余動作完全是由虛擬機主導和控制的。到了初始化階段,才真正開始執(zhí)行類中定義的 Java 程序代碼。初始階段是執(zhí)行類構造器?() 方法的過程。

    三. 類加載器

    虛擬機設計團隊把類加載階段中的「通過一個類的全限定名來獲取描述此類的二進制字節(jié)流」這個動作放到 Java 虛擬機外部去實現(xiàn),以便讓應用程序自己決定如何去獲取所需要的類。實現(xiàn)這個動作的代碼模塊稱為「類加載器」。

    類與類加載器

    對于任意一個類,都需要由加載它的類加載器和這個類本身一同確立其在 Java 虛擬機的唯一性,每個類加載器都擁有一個獨立的類名稱空間。也就是說:比較兩個類是否「相等」,只要在這兩個類是由同一個類加載器加載的前提下才有意義,否則,即使這兩個類來源于同一個 Class 文件,被同一個虛擬機加載,只要加載它們的類加載器不同,那這兩個類就必定不相等。

    雙親委派模型

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

    從 Java 開發(fā)者的角度來看,類加載器可以劃分為:

    • 啟動類加載器(Bootstrap ClassLoader):這個類加載器負責將存放在?<java_home>\lib 目錄中的類庫加載到虛擬機內(nèi)存中。啟動類加載器無法被 Java 程序直接引用,用戶在編寫自定義類加載器時,如果需要把加載請求委派給啟動類加載器,那直接使用 null 代替即可;

    • 擴展類加載器(Extension ClassLoader):這個類加載器由?sun.misc.Launcher$ExtClassLoader實現(xiàn),它負責加載?<java_home>\lib\ext 目錄中,或者被 java.ext.dirs 系統(tǒng)變量所指定的路徑中的所有類庫,開發(fā)者可以直接使用擴展類加載器;

    • 應用程序類加載器(Application ClassLoader):這個類加載器由?sun.misc.Launcher$App-ClassLoader?實現(xiàn)。getSystemClassLoader()?方法返回的就是這個類加載器,因此也被稱為系統(tǒng)類加載器。它負責加載用戶類路徑(ClassPath)上所指定的類庫。開發(fā)者可以直接使用這個類加載器,如果應用程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認的類加載器。

    我們的應用程序都是由這 3 種類加載器互相配合進行加載的,在必要時還可以自己定義類加載器。它們的關系如下圖所示:

    ?

    上圖中所呈現(xiàn)出的這種層次關系,稱為類加載器的雙親委派模型(Parents Delegation Model)。雙親委派模型要求除了頂層的啟動類加載器以外,其余的類加載器都應當有自己的父類加載器。

    雙親委派模型的工作過程是這樣的:如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,每一個層次的類加載器都是如此,因此所有的加載請求最終都應該傳送到頂層的啟動類加載器中,只有當父類加載器反饋自己無法完成這個類加載請求(它的搜索范圍中沒有找到所需的類)時,子加載器才會嘗試自己去加載。

    這樣做的好處就是 Java 類隨著它的類加載器一起具備了一種帶有優(yōu)先級的層次關系。例如 java.lang.Object,它放在 rt.jar 中,無論哪一個類加載器要加載這個類,最終都是委派給處于模型頂端的啟動類加載器來加載,因此 Object 類在程序的各種類加載器環(huán)境中都是同一個類。相反,如果沒有使用雙親委派模型,由各個類加載器自行去加載的話,如果用戶自己編寫了一個稱為 java.lang.Object 的類,并放在程序的 ClassPath 中,那系統(tǒng)中將會出現(xiàn)多個不同的 Object 類,Java 類型體系中最基本的行為也就無法保證了。

    雙親委派模型對于保證 Java 程序運行的穩(wěn)定性很重要,但它的實現(xiàn)很簡單,實現(xiàn)雙親委派模型的代碼都集中在 java.lang.ClassLoader 的 loadClass() 方法中,邏輯很清晰:先檢查是否已經(jīng)被加載過,若沒有則調(diào)用父類加載器的 loadClass() 方法,若父加載器為空則默認使用啟動類加載器作為父加載器。如果父類加載失敗,拋出 ClassNotFoundException 異常后,再調(diào)用自己的 findClass() 方法進行加載。

    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // 首先,檢查請求的類是不是已經(jīng)被加載過 Class<?> c = findLoadedClass(name); if (c == null) { try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // 如果父類拋出 ClassNotFoundException 說明父類加載器無法完成加載 } if (c == null) { // 如果父類加載器無法加載,則調(diào)用自己的 findClass 方法來進行類加載 c = findClass(name); } } if (resolve) { resolveClass(c); } return c; }

    關于類文件結構和類加載就通過連續(xù)的兩篇文章介紹到這里了,下一篇我們來聊聊「虛擬機的字節(jié)碼執(zhí)行引擎」。

    參考資料:

    • 《深入理解 Java 虛擬機:JVM 高級特性與最佳實踐(第 2 版)》

    如果你喜歡我的文章,就關注下我的公眾號?BaronTalk?、?知乎專欄?或者在?GitHub?上添個 Star 吧!

    • 微信公眾號:BaronTalk
    • 知乎專欄:https://zhuanlan.zhihu.com/baron
    • GitHub:https://github.com/BaronZ88





    轉載于:https://www.cnblogs.com/baronzhang/p/11108333.html

    總結

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

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

    主站蜘蛛池模板: 中文字幕第7页 | 深爱激情综合 | 重口变态虐黄网站 | 星铁乱淫h侵犯h文 | 操你啦免费视频 | 国产一区在线视频观看 | 中文字幕日产乱码中 | 亚洲爱爱网站 | 国产chinese中国hdxxxx | 日韩精品一区二区亚洲av性色 | 激情内射人妻1区2区3区 | 亚洲精品一区二区三区四区五区 | 精品一区二区三区日韩 | 亚洲av永久无码精品放毛片 | 九九久久网 | 亚洲天天操 | 国产最新毛片 | 重口变态虐黄网站 | 欧美激情一级精品国产 | 69亚洲乱人伦 | 天天干天天要 | 综合网激情 | 日韩精品字幕 | 一级黄色特级片 | 亚洲欧美日韩免费 | 国产又粗又猛又色 | 亚洲av无码国产精品色午夜 | 女av在线| 日韩免 | 特黄大片又粗又大又暴 | 欧美伊人| 少妇户外露出[11p] | 老熟妇仑乱一区二区视频 | 九九久视频 | 中文字幕无码日韩专区免费 | 一级片国产 | 激情视频亚洲 | 国产在线伊人 | 日本一二三区在线视频 | 久久久精品久久久 | 日韩人妻精品一区二区三区视频 | 欧美区在线 | 久久久综合av | 爱的天堂| 国产中文字幕在线免费观看 | 韩国av一区二区三区 | 国产高清一区二区三区 | 日日摸日日添日日碰9学生露脸 | 人乳喂奶hd无中字 | 欧美黄色成人 | 黑鬼巨鞭白妞冒白浆 | 日本在线h | 综合网久久 | 老局长的粗大高h | 黄色av软件 | 久久一二三四区 | 亚洲国产黄色片 | 蜜桃传媒一区二区亚洲 | 日韩v欧美 | 亚洲欧美一区二区视频 | 四虎国产精品成人免费入口 | 精品视频一区二区三区 | 日本学生初尝黑人巨免费视频 | 张柏芝亚洲一区二区三区 | 精品国产一级久久 | 精品处破女学生 | 在线欧美视频 | 国产精品一级无码 | 无码精品人妻一二三区红粉影视 | 粉嫩av四季av绯色av | 欧美bbbbb | 精品久久久久一区 | 黄色1级片 | 色秀视频在线观看 | 让人下面流水的视频 | 中国女人真人一级毛片 | 日本少妇性生活 | 最新av电影网站 | 黑人玩弄人妻一区二区三区免费看 | 老妇裸体性激交老太视频 | 国产成人无码AA精品区 | 成人免费黄色大片 | 一区二区三区四区在线观看视频 | 黄色同人网站 | 日韩第二页 | 亚洲天堂男人天堂 | 久久久久国色av免费观看性色 | 久久性爱视频网站 | 久久一区视频 | 91国偷自产一区二区三区老熟女 | 97超碰导航 | www成人免费视频 | 日本不卡一区二区三区在线观看 | 久久免费电影 | 亚洲AV乱码国产精品观看麻豆 | 好色先生视频污 | 丁香五色月 | 日本在线精品视频 | 性囗交免费视频观看 |