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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

JVM——详解类加载过程

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

導航

  • 一、過程概述
  • 二、Loading
    • 2.1 類加載器
    • 2.2 雙親委派機制
    • 2.3 類在內存中的結構
  • 三、Linking
  • 四、Initializing

一、過程概述

java 源文件編譯后會生成一個 .class文件存儲在硬盤上。

在程序運行時,會將用到的類文件加載到 JVM 內存中。從磁盤到內存的過程總共分為三個步驟:加載、連接、初始化。

  • Loading
  • Linking
  • Initializing
  • 二、Loading

    Loading 過程是把一個 class 文件加載到內存中去。

    2.1 類加載器

    JVM 加載類的方式是按需動態加載,采用雙親委派機制

    認識幾種系統提供的類加載器:

  • Bootstrap 啟動類加載器,負責加載指定目錄——JAVA_HOME/lib下的 rt.jar、charset.jar 等核心類庫,由 C++實現,是JVM 的不可分割的一部分。類加載范圍可以在 Launcher 類中查看:

  • ExtClassLoader 擴展類加載器,負責加載指定目錄——JAVA_HOME/lib/ext 下的擴展包,或者也可以由 -Djava.ext.dirs 參數指定。類加載范圍可以在 Launcher 類中查看:

  • AppClassLoader 應用類加載器,加載用戶應用的 classpath 下的 class 文件,這是應用程序的默認類加載器,用戶自定義的類都是通過這個類加載器來加載。類加載范圍可以在 Launcher 中查看:

  • 自定義類加載器,開發者自定義的 ClassLoader,繼承自 ClassLoader 抽象類,并重寫 findClass(…) 。

  • 類加載器(除 C++實現的 Bootstrap 外)本身就是一個普通的 class,JVM 所有的 class 都是被類加載器加載到內存的。

    public class TestLoadClass {public static void main(String[] args) {System.out.println(TestLoadClass.class.getClassLoader());System.out.println(TestLoadClass.class.getClassLoader().getParent());// Bootstrap 由 C++ 實現,Java 中沒有具體的類與之對應,故返回 nullSystem.out.println(TestLoadClass.class.getClassLoader().getParent().getParent());} } output: sun.misc.Launcher$AppClassLoader@58644d46 sun.misc.Launcher$ExtClassLoader@4554617c null

    2.2 雙親委派機制

    JVM 加載類時處于安全考慮,基礎類和擴展類等,都必須由指定的類加載器來加載,不同的類加載器有自己的命名空間,同一個類,如果由不同的類加載器加載,會在內存中存在多份類對象。也正因如此,JVM 的類加載機制要求諸如 java.lang.Object 這種基礎類必須由最基礎的 Bootstrap 來加載。

    因此,整個 Loading 的過程就成了:底層類加載器收到類加載請求后,必須將請求層層傳遞給父級加載器檢查,確認是否應該由父級加載器加載,若由于父加載器的指定類路徑中沒有該類文件,就會再層層向下返回,最終才會去加載:

    Tip:注意,AppClassLoader 的父加載器是 ExtClassLoader,ExtClassLoader的父加載器是Bootstrap 加載器。
    這里的父加載器并不是 Java 多態中語法的 extends 繼承關系,而是一種架構上的層級關系,AppClassLoader 和 ExtClassLoader 之間沒有任何繼承關系,它們在語法上,都繼承自 ClassLoader 抽象類,實際上 ClassLoader 中維護了一個 ClassLoader parent 引用,這才是 “雙親” 的真實面目,即 AppClassLoader 的父加載器實際上是其內部的一個組合對象

    2.3 類在內存中的結構

    加載的時候,創建了兩塊內容,第一塊內容是把 Xxx.class 二進制扔到內存中,第二塊內容是生成一個 Class 類的對象,該對象中的變量會指向前一塊的實際內存地址(這一步實際上是Resolution 的過程)。

    三、Linking

    Linking,連接,這是一個大的步驟,其中又分為三個小步驟:

  • Verification 驗證
  • Preparation 準備
  • Resolution 解析
  • 驗證:校驗 class 文件格式是否符合 jvm 規范,如開頭的魔數等。
    準備:將 class 中的靜態變量賦默認值,所謂默認值,舉個例子,int 類型默認值是 0,String 類型默認值是 null。
    解析:把class 文件常量池中的符號引用轉化為直接內存地址。

    四、Initializing

    初始化,區別于 Linking 中的 Preparation ,此過程將靜態變量賦初始值。比如:

    public static int num = 8;

    這個 num 靜態變量會在 Preparation 階段賦值 0 ,在 Initializing 階段賦值 8。

    Java初始化的時機,JVM規范中有明確規定,自然,加載也一定是在初始化之前完成。JVM規范中定義了以下這些必須初始化完畢的場景:

  • new
  • 讀取和設置 static 變量,只觸發直屬類的初始化(例如,子類直接引用父類中的 static 變量,只初始化父類)
  • 調用 static 方法
  • 子類初始化之前,父類必須完成初始化
  • main 函數所在的類在執行之前必須完成初始化
  • 通過反射獲取類信息
  • 注意:對于 static final 類型的屬性,在編譯之后即存儲在字節碼文件的常量池中,直接引用它不會觸發初始化。

    記憶技巧:

  • new 是創建對象,而對象的創建一定需要類信息的支持
  • static 變量和方法,又稱為類變量、類方法,它們都需要類指針來訪問。
  • main也屬于static 方法
  • 子類是父類的擴展,子類都要初始化了,父類當然一定要先初始化
  • 反射是使用類信息的一種技術,當然需要先初始化類
  • 總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。