JVM學習 類載入子系統

来源:https://www.cnblogs.com/shuisanya/archive/2022/09/12/16686379.html
-Advertisement-
Play Games

JVM 嗶哩嗶哩 尚矽谷視頻 宋紅康老師 ==Java代碼執行流程== ==簡圖== ==詳細圖== 1、類載入子系統 ==類載入器子系統的作用== 類載入器子系統負責從文件系統或者網路中載入Class文件,class文件在文件開頭有特定的文件標識 ClassLoader 只負責 class 文件的 ...


JVM

嗶哩嗶哩 尚矽谷視頻 宋紅康老師


Java代碼執行流程

簡圖

詳細圖


1、類載入子系統

類載入器子系統的作用

  • 類載入器子系統負責從文件系統或者網路中載入Class文件,class文件在文件開頭有特定的文件標識
  • ClassLoader 只負責 class 文件的載入,至於它是否可以運行,則由Execution Engine決定
  • 載入的類信息存放於一塊稱為方法區的記憶體空間。除了類的信息外,方法區中還會存放運行時常量池信息,可能還包括字元串字面量和數字常量(這部分常量信息是Class文件中常量池的部分映射)

類的載入過程圖


1.1、載入階段

載入

  • 通過一個類型的許可權定名獲取定義類的二進位位元組流
  • 將這個位元組流所代表的靜態存儲結構轉化為方法區的運行時數據結構
  • 在記憶體中生成一個代表這個類的java.lang.Class對象,作為方法區這個類的各種數據的訪問入口

1.2、鏈接階段

驗證(Verify)

  • 目的在於確保Class文件的位元組流中包含信息符合當前虛擬機要求,保證被載入類的正確性,不會危害虛擬機自身安全
  • 主要包括四種驗證,文件格式驗證,元數據驗證,位元組碼驗證,符號引用驗證

準備(Prepare)

  • 為類變數分配記憶體並且設置該類變數的預設初始值,即零值
  • 這裡不包括用final修飾的static,因為final在編譯的時候就分配了,準備階段會顯示初始化
  • 這裡不會為實例變數分配初始化,類變數會分配在方法區中,而實例變數是會隨著對象一起分配到Java堆中

解析(Resolve)

  • 將常量池內的符號引用轉換為直接引用過程
  • 事實上,解析操作往往會伴隨著JVM在執行完初始化之後再執行
  • 符號引用就是一組符號來描述引用的目標,符號引用的字面量形式明確定義在《java虛擬機規範》的class文件格式中,直接引用就是直接指向目標的指針、相對偏移量或一個間接定位到目標的句柄
  • 解析動作主要針對類或介面、欄位、類方法、介面方法、方法類型等,對應常量池中的CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等。

1.3、初始化階段

初始化

  • 初始化階段就是執行類構造器方法()方法的過程
  • 此方法不需定義,是javac編譯器自動收集類中的所有類變數的賦值動作和靜態代碼塊中的語句合併而來
  • 構造器方法中指令按語句在源文件中出現的順序執行
  • ()不同於類的構造器。(關聯:構造器是虛擬機視角下的())
  • 若該類具有父類,JVM會保證子類的()執行前,父類的()已經執行完畢
  • 虛擬機必須保證一個類的()方法在多線程下被同步加鎖

安裝 jclasslib is a bytecode viewer 來查看class位元組碼文件(Ider插件集成了的)


1.4、類載入器的分類

  1. JVM支持兩種類型的類載入器,分別是引導類載入器(Bootstrap ClassLoader)自定義類載入器(User-Defined ClassLoader)

  2. 從概念上來講,自定義類載入器一般指的是程式中由開發人員自定義的一類載入器,但是Java虛擬機規範卻沒有這麼定義,而是將所有派生於抽象類ClassLoader的類載入器都劃分為自定義類載入器

  3. 無論類載入器的類型如何劃分,在程式中我們最常見的類載入器始終只有3個:

    這裡的四者之間的關係是包含關係,不是下層下層關係,也不是子父類關係的繼承關係

測試:

public class ClassLoaderTest {
    public static void main(String[] args) {
        //獲取系統類載入器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);

        //獲取其上層,擴展類載入器
        ClassLoader extClassLoader = systemClassLoader.getParent();
        System.out.println(extClassLoader);

        //獲取其上層:獲取不到引導類載入器
        ClassLoader bootstrapClassLoader = extClassLoader.getParent();
        System.out.println(bootstrapClassLoader);

        //用戶自定義類的載入器是誰
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader);

        //String這個類是誰載入的:引導類載入器
        ClassLoader stringClassLoader = String.class.getClassLoader();
        System.out.println(stringClassLoader);
    }

    /*
     * 結果:
     * sun.misc.Launcher$AppClassLoader@18b4aac2
     * sun.misc.Launcher$ExtClassLoader@1b6d3586
     * null
     * sun.misc.Launcher$AppClassLoader@18b4aac2
     * null
     */
}

Java的核心類庫都是引導類載入器載入的

虛擬機自帶的載入器

  • 啟動類載入器(引導類載入器:Bootstrap ClassLoader)
    • 這個類載入使用C/C++語言實現的,嵌套在JVM內部
    • 它用來載入Java的核心庫(JAVA_HOME/jre/lib/rt.jar、resources.jar或sun.boot.class.path路徑下的內容),用於提供JVM自身需要的類)
    • 並繼承自java.lang.ClassLoader,沒有父載入器
    • 載入擴展類和應用程式類載入器,並指定為他們的父類載入器
    • 出於安全的考慮,Bootstrap啟動類載入器只載入包名為java、javax、sun等開頭的類
  • 擴展類載入器(Extension ClassLoader)
    • Java語言編寫,由sun.misc.Launcher$ExtClassLoader實現
    • 派生於ClassLoader類
    • 父類載入器為啟動類載入器
    • 從java.ext.dirs系統屬性所指定的目錄中載入類庫,或從JDK的安裝目錄的jre/lib/ext子目錄(擴展目錄)下載入類庫。如果用戶創建的JAR放在此目錄下,也會自動由擴展類載入器載入。
  • 應用程式類載入器(系統類載入器,AppClassLoader)
    • Java語言編寫,由sun.misc.Launcher$AppClassLoader實現
    • 派生於ClassLoader類
    • 父類載入器為擴展類載入器
    • 它負責載入環境變數classpath或系統屬性 java.class.path 指定路徑下的類庫
    • 該類載入是程式中預設的類載入器,一般來說,Java應用的類都是由它來完成載入的
    • 通過classLoader#getSystemClassLoader()方法可以獲取該類載入器

測試:

package com.mhy.day01;

import sun.misc.Launcher;
import java.net.URL;

public class ClassLoaderTest01 {
    public static void main(String[] args) {
        //引導類載入器載入哪些路徑下的文件
        System.out.println("引導類載入器載入的路徑:");
        URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
        for (URL urL : urLs) {
            System.out.println(urL);
        }
        //擴展類載入器載入哪些路徑下的文件
        System.out.println("擴展類載入器載入的路徑:");
        String property = System.getProperty("java.ext.dirs");
        for(String p : property.split(";")){
            System.out.println(p);
        }

        /*結果:
            引導類載入器載入的路徑:
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/lib/resources.jar
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/lib/rt.jar
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/lib/sunrsasign.jar
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/lib/jsse.jar
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/lib/jce.jar
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/lib/charsets.jar
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/lib/jfr.jar
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/classes
            擴展類載入器載入的路徑:
            F:\Program Files\JavaIDEA\jdk\jre\lib\ext
            C:\WINDOWS\Sun\Java\lib\ext
         */
    }
}

1.5、雙親委派機制

工作原理

  1. 如果一個類載入器收到一個類載入的請求,它並不會自己先去載入,而是把這個請求委托給父類的載入器去執行
  2. 如果父類載入器還存在其父類載入器,則進一步向上委托,依次遞歸,最終的請求回到達啟動類載入器
  3. 如果父類載入器可以完成類載入任務,則成功返回;倘若父類載入器不能完成載入,子類載入器才會嘗試去載入,這就是雙親委派機制

測試:

這裡在src文件下創建一個java.lang.String和自帶的String同路徑

package java.lang;

public class String {
    static {
        System.out.println("這是我們自己建立的String");
    }
    
    //如果在這個裡面執行main方法
    /*
    錯誤: 在類 java.lang.String 中找不到 main 方法, 請將 main 方法定義為:
    public static void main(String[] args)
    否則 JavaFX 應用程式類必須擴展javafx.application.Application
     */
    public static void main(String[] args) {
        System.out.println("xxx");
    }
}

再在測試類中進行測試,看使用的String到底來自哪個String

package com.mhy.day01;

public class ClassLoaderTest02 {
    public static void main(String[] args) {
        String xx = new String();
        System.out.println("執行了該程式");
    }

    /*結果:
     * 執行了該程式
     */
}

1.6、類的主動使用和被動使用

  • 主動使用主要分為7種:

    • 創建類的實例

    • 訪問某個類或介面的靜態變數,或者對該靜態變數賦值

    • 調用該類的靜態方法

    • 反射(比如Class.forName("路徑")))

    • 初始化一個類的子類

    • Java虛擬機啟動時被表明為啟動類的類

    • JDK7提供的動態語言的支持:

      java.lang.invoke,MethodHandle實例的解析結果

      REF_getStatic、REF_putStatic、REF_invokeStatic句柄對應的類沒有初始化,則初始化

  • 除了以上7種外,其他的Java對類的使用,就是被動使用


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 組合模式(Composite Pattern),又叫部分整體模式,是用於把一組相似的對象當作一個單一的對象。組合模式依據樹形結構來組合對象,用來表示部分以及整體層次。這種類型的設計模式屬於結構型模式,它創建了對象組的樹形結構。 ...
  • 反射 筆記目錄:(https://www.cnblogs.com/wenjie2000/p/16378441.html) 一個需求引出反射 請看下麵的問題 根據配置文件 re.properties 指定信息,創建對象並調用方法(以下為文件內容) classfullpath=com.hspedu.Ca ...
  • 一、多線程概述 1.1、進程和線程的概念 1.1.1、進程 進程是執行程式的一次執行過程,是一個動態的過程,是一個活動的實體,是系統資源分配的單位 一個應用程式的運行就可以被看做是一個進程 1.1.2、線程 線程,是運行中的實際的任務執行者,一般的,一個進程中包含了多個可以同時運行的線程 線程就是獨 ...
  • JavaIO流04 4.常用的類03 4.4節點流和處理流02 4.4.5對象處理流-ObjectInputStream和ObjectOutputStream 1.序列化和反序列化 例子1: 看一個需求 將int num= 100這個int 類型的數據保存到文件中,註意不是100 數字,而是int ...
  • 傳送門: https://www.cnblogs.com/greentomlee/p/12314064.html github: Leezhen2014: https://github.com/Leezhen2014/python_deep_learning 在第二篇中介紹了用數值微分的形式計... ...
  • 今年教師節前夕,我特意用Python做了個學生點名系統,非常好用,送給各科老師、輔導員當節日禮物,老師們都喜滋滋,說平常逃課就原諒我了,我心想,這次畢業應該不是問題了~ 本文背景 根據我的調查,現在的學生大部分都很積極,會主動舉手回答問題。但是,也會遇到一些不好的情況,比如年級越高主動舉手的人越少, ...
  • 前言 嗨嘍~大家好呀,這裡是魔王吶 ! 壁紙,有多種的類別和各種不同的風格,如: 風景、美女、唯美、動漫、花卉、節日等適合您的高清桌面壁紙 今天我們就來採集一下叭~ 環境使用: Python 3.8 解釋器 Pycharm 編輯器 需安裝python第三方模塊 : requests win + R ...
  • Web的8種(6+2)元素+定位方法 - id : id屬性 - name : name屬性 - class_name : - tag_name :標簽名 - css定位表達式: 局部html代碼 <input type="text" class="s_ipt" name="wd" id="kw" ...
一周排行
    -Advertisement-
    Play Games
  • 基於.NET Framework 4.8 開發的深度學習模型部署測試平臺,提供了YOLO框架的主流系列模型,包括YOLOv8~v9,以及其系列下的Det、Seg、Pose、Obb、Cls等應用場景,同時支持圖像與視頻檢測。模型部署引擎使用的是OpenVINO™、TensorRT、ONNX runti... ...
  • 十年沉澱,重啟開發之路 十年前,我沉浸在開發的海洋中,每日與代碼為伍,與演算法共舞。那時的我,滿懷激情,對技術的追求近乎狂熱。然而,隨著歲月的流逝,生活的忙碌逐漸占據了我的大部分時間,讓我無暇顧及技術的沉澱與積累。 十年間,我經歷了職業生涯的起伏和變遷。從初出茅廬的菜鳥到逐漸嶄露頭角的開發者,我見證了 ...
  • C# 是一種簡單、現代、面向對象和類型安全的編程語言。.NET 是由 Microsoft 創建的開發平臺,平臺包含了語言規範、工具、運行,支持開發各種應用,如Web、移動、桌面等。.NET框架有多個實現,如.NET Framework、.NET Core(及後續的.NET 5+版本),以及社區版本M... ...
  • 前言 本文介紹瞭如何使用三菱提供的MX Component插件實現對三菱PLC軟元件數據的讀寫,記錄了使用電腦模擬,模擬PLC,直至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1. PLC開發編程環境GX Works2,GX Works2下載鏈接 https:// ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • 1、jQuery介紹 jQuery是什麼 jQuery是一個快速、簡潔的JavaScript框架,是繼Prototype之後又一個優秀的JavaScript代碼庫(或JavaScript框架)。jQuery設計的宗旨是“write Less,Do More”,即倡導寫更少的代碼,做更多的事情。它封裝 ...
  • 前言 之前的文章把js引擎(aardio封裝庫) 微軟開源的js引擎(ChakraCore))寫好了,這篇文章整點js代碼來測一下bug。測試網站:https://fanyi.youdao.com/index.html#/ 逆向思路 逆向思路可以看有道翻譯js逆向(MD5加密,AES加密)附完整源碼 ...
  • 引言 現代的操作系統(Windows,Linux,Mac OS)等都可以同時打開多個軟體(任務),這些軟體在我們的感知上是同時運行的,例如我們可以一邊瀏覽網頁,一邊聽音樂。而CPU執行代碼同一時間只能執行一條,但即使我們的電腦是單核CPU也可以同時運行多個任務,如下圖所示,這是因為我們的 CPU 的 ...
  • 掌握使用Python進行文本英文統計的基本方法,並瞭解如何進一步優化和擴展這些方法,以應對更複雜的文本分析任務。 ...
  • 背景 Redis多數據源常見的場景: 分區數據處理:當數據量增長時,單個Redis實例可能無法處理所有的數據。通過使用多個Redis數據源,可以將數據分區存儲在不同的實例中,使得數據處理更加高效。 多租戶應用程式:對於多租戶應用程式,每個租戶可以擁有自己的Redis數據源,以確保數據隔離和安全性。 ...