JVM系列(一)——類加載器以及雙親委託機制

寫在前面

本文主要介紹了四種類加載器,以及算清委託機制。文章可能還有很多不足,請大家諒解,歡迎大佬提意見。

本文使用到的東西

  1. java

1.類加載器

1.1 類加載器作用:
類加載器負責從文件或者網絡中加載Class信息,加載的類信息存放於方法區的內存空間。

1.2 啓動類加載器(BootStrap ClassLoader):

  1. C++實現,是虛擬機的一部分;
  2. 負責加載“%JAVA_HOME%\lib”目錄中,或者-Xbootclasspath參數指定路徑中的類庫到虛擬機;
  3. 無法被java程序直接引用。

1.3 擴展類加載器(Extension ClassLoader):
獨立於JVM,由sun.misc.Launcher$ExtClassLoader實現,加載”%JAVA_HOME%\lib\ext”目錄中,或者java.ext.dirs系統變量指定的路徑中的所有類庫,該類加載器無法被java程序直接引用。

1.4 應用程序類加載器(Application ClassLoader):
獨立於JVM,由sun.misc.Launcher$AppClassLoader實現,也叫系統類加載器。負責加載用戶類路徑(classpath)上指定的類庫,可以直接使用,一般情況下是默認的類加載器。

1.5 啓動類加載器(BootStrap ClassLoader):
獨立於JVM,需要繼承於java.lang.ClassLoader抽象類,複寫Class<?> findClass(String name)方法。讀取類文件的二進制數據流,通過Class<?> defineClass方法加載類。

2.雙親委託機制

在加載類時必須先交給父加載器加載,父加載器不存在則交給啓動類加載器加載,還沒加載到再自己加載;目的是爲了避免類的重複加載。

已知java中類加載器都繼承於java.lang.ClassLoader抽象類,通過loadClass(String name)方法加載類:

loadClass(String name):

//加載類的方法
public Class<?> loadClass(String name) throws ClassNotFoundException {
	//調用了loadClass(name, resolve)方法,false表示不解析類
    return loadClass(name, false);
}

loadClass(name, resolve):

    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 檢查類是否已經加載
            Class<?> c = findLoadedClass(name);
            // 未加載情況
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                	/**
                	* 雙親委託
                	* 判斷父類加載器是否存在,存在則交給父類加載器加載
                	* 不存在父加載器則交給啓動類加載器(BootStrap ClassLoader)加載
                	*/
                    if (parent != null) {
                    	// 父類加載器加載
                        c = parent.loadClass(name, false);
                    } else {
                    	// 啓動類加載器加載
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    long t1 = System.nanoTime();
                    // 如果還沒有加載到類,則交給findClass(name)來加載
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
            	// 解析類
                resolveClass(c);
            }
            return c;
        }
    }
    // 自定義類時交給我們來複寫
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }

通過閱讀源碼我們可以知道,我們只需要繼承ClassLoader抽象類,複寫findClass(String name)即可實現自定義類加載器。而複寫loadClass(String name, boolean resolve)方法則可以破壞雙親委託機制。

3.總結

本文簡單描述了JVM的類加載器以及雙親委託,從ClassLoader源碼層面分析了類加載機制。有不清楚的地方歡迎評論留言,看到的我都會回覆的。本文到此結束,有什麼不足的地方請大家不吝指正。

發佈了44 篇原創文章 · 獲贊 29 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章