ClassLoader加載機制(源碼淺析)

類加載機制

加載是指查找字節流,並且據此創建類的過程。加載需要藉助類加載器,在 Java 虛擬機中,類加載器使用了雙親委派模型,即接收到加載請求時,會先將請求轉發給父類加載器。

ClassLoader雙親委派機制

在這裏插入圖片描述
類加載器加載類步驟:

  1. 首先會自底向上檢測是否加載過此Class(即在緩存區中是否有此Class),如果有直接返回Class對象;
  2. 判斷父加載器是否存在,如果存在父加載器,則請求父類加載器來載入此Class,如果成功則返回Class對象;如果不成功則使用子類加載器來載入此Class,如果成功則返回Class對象,如果不成功則拋出ClassNotFoundException()異常;
  3. 如果不存在父類加載器(要麼父類加載器是根加載器;要麼本身就是根加載器),請求根類加載器是來載入此Class,如果成功則返回Class對象,如果不成功則拋出ClassNotFoundException()異常;

源碼淺析(關鍵方法)

loadClass(String name, boolean resolve)
name是類的名字,resolve是解析

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
404行會進入一個同步鎖,因爲有可能涉及到多個線程調用一個ClassLoader加載同一個類,保證線程安全,避免衝突;

406行Class<?> c = findLoadedClass(name);會尋找曾經是否加載過目標Class,如果有會直接跳過407的if和432的if,直接return c;,即返回目標Class對象;

如果沒有加載過目標Class,會直接進入407行的 if,408行會進入計時(可以忽略);則會判斷parent是否爲空,如果parent不爲null,那麼當前ClassLoader的父加載器,再次進入loadClass方法即401行;

如果當父加載器是BootStrapClassLoader時或者自己本身就是BootStrapClassLoader,由於BootStrapClassLoader是C++編寫的,parent則會返回null

進入412行的elsec = findBootstrapClassOrNull(name);去查找BootStrapClassLoader有沒有載入過目標Class;若載入過,返回Class對象;否則會進入BootStrapClassLoader目錄下掃描是有目標Class,如果有返回,沒有就會返回;

進入420行的ifc = findClass(name);會在當前ClassLoader目錄中去查找是否有目標Class;如果有就裝載目標Class並返回,如果沒有就會輪到子類ClassLoader來查找,最終會到自定義ClassLoader去查找是否有目標Class,如果有返回,沒有就會拋出ClassNotFoundException()異常;

ClassLoader之間的關係

package ClassLoader;

public class ClassLoaderDemo {

    public static void main(String[] args) {
        Class c = ClassLoaderDemo.class;

        //由於是使用系統類加載器(非自定義加載器)來加載ClassLoaderDemo類,應該輸出AppClassLoader
        System.out.println(c.getClassLoader());
        //AppClassLoader的父加載器應該是ExtClassLoader
        System.out.println(c.getClassLoader().getParent());
        //ExtClassLoader的父加載器應該是BootStrapClassLoader(BootStrapClassLoader應該輸出null)
        System.out.println(c.getClassLoader().getParent().getParent());

    }
}

在這裏插入圖片描述

自定義ClassLoader——>AppClassLoader——>ExtClassLoader——>BootStrapClassLoader(null)

Tips:爲什麼BootStrapClassLoader是null?

在上面的413行代碼中提到c = findBootstrapClassOrNull(name);
在這裏插入圖片描述
在這裏插入圖片描述
native會去調用本地庫或者外置都非Java代碼(在openjdk中可以查看)

爲什麼要使用雙親委派機制加載類?

避免多份同樣字節碼重複加載,內存是有限的,沒有必要保存相同的Class對象。

例如:System.out.println();

類A打印時會加載一次System類;類B打印時又會加載一次System類,那麼內存中就會存在兩份相同的System字節碼,造成沒必要的內存消耗;

如果使用雙親委派機制加載類,加載過後就不會再重複加載相同的Class;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章