1. 程式人生 > 實用技巧 >JVM - 類載入過程

JVM - 類載入過程

類載入主要有三個過程:loading 、linking 、initializing

其中linking又分為三個步驟:verification 、preparation 、resolution

1:loading是把一個class檔案載入到記憶體中

2:接下來就是Linking,分為三小步

  2.1:verification 用來校驗載入進來的class檔案是否符合class檔案標準,如果不符合直接拒絕

  2.2:preparation 將class檔案的靜態變數賦預設值而不是初始值,如 static int i = 8;這個步驟並不是將 i 賦值為8,而是賦值預設值0

  2.3:resolution 把class檔案常量池中用到的符號引用轉換成記憶體地址,可以訪問到的內容

3:initialzing 成為初始化,靜態變數這個時候才會被賦值為初始值

下面為loading的過程圖

類載入器的載入過程是分成不同的層次來載入的,不同的類載入器載入不同的class檔案,Bootstrap > Extension > App > Custom(自定義類載入器)

1:第一個類載入器:Bootstrap 稱為啟動類載入器,是Java類載入層次中最頂層的類載入器,負責載入JDK中的核心類庫

2:第二個類載入器:Extension 是用來載入擴充套件類的,主要載入Java的擴充套件類庫,預設載入JAVA_HOME/jre/lib/ext/目錄下的所有jar包

3:第三個類載入器:Application 稱為系統類載入器,負責在JVM啟動時,載入來自Java中的classpath或者java.class.path系統屬性

或者

          CLASSPATH作業系統屬性所指定的jar類包和類路徑

4:第四個類載入器:CustomClassLoader(自定義載入器)

文字描述:

用比較通俗的話來解釋loading這個過程,當有一個類需要被載入時,首先要判斷這個類是否已經被載入到記憶體,判斷載入與否的過程是有順序的,

如果有自己定義的類載入器,會先到custom class loader 的cache(快取)中去找是否已經載入,若已載入直接返回結果,

否則到App的cache中查詢,如果已經存在直接返回,如果不存在,到Extension中查詢,存在直接返回,

不存在繼續向父載入器中尋找直到Bootstrap頂層,

如果依然沒找到,那就是沒有載入器載入過這個類,需要委派對應的載入器來載入,

先看看這個類是否在自己的載入範圍內,如果是直接載入返回結果,若不是繼續向下委派,以此類推直到最下級,

如果最終也沒能載入,就會直接拋異常ClassNotFoundException,這就是雙親委派模式。

  public static void main(String[] args) {
System.out.println(
"----------------Bootstrap載入類----------------"); String property = System.getProperty("sun.boot.class.path"); String s = property.replaceAll(";", System.lineSeparator()); System.out.println(s); System.out.println("-------------------Ext載入類-------------------"); String property1 = System.getProperty("java.ext.dirs"); String s1 = property1.replaceAll(";", System.lineSeparator()); System.out.println(s1); System.out.println("-------------------App載入類-------------------"); String property2 = System.getProperty("java.class.path"); String s2 = property2.replaceAll(";", System.lineSeparator()); System.out.println(s2); }

----------------Bootstrap載入類----------------
C:\Program Files\Java\jdk1.8.0_201\jre\lib\resources.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\rt.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\sunrsasign.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\jsse.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\jce.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\charsets.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\jfr.jar
C:\Program Files\Java\jdk1.8.0_201\jre\classes


-------------------Ext載入類-------------------
C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext
C:\Windows\Sun\Java\lib\ext


-------------------App載入類-------------------
C:\Program Files\Java\jdk1.8.0_201\jre\lib\charsets.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\deploy.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\access-bridge-64.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\cldrdata.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\dnsns.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\jaccess.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\jfxrt.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\localedata.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\nashorn.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunec.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunjce_provider.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunmscapi.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\sunpkcs11.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext\zipfs.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\javaws.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\jce.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\jfr.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\jfxswt.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\jsse.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\management-agent.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\plugin.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\resources.jar
C:\Program Files\Java\jdk1.8.0_201\jre\lib\rt.jar
E:\Project\Java\out\production\Java
D:\IntelliJ IDEA\IntelliJ IDEA 2019.2.4\lib\idea_rt.jar

為什麼要搞雙親委派?

主要是為了安全,這裡可以使用反證法,如果任何載入器都可以把Class載入到記憶體中,我們就可以自定義載入器來載入java.lang.string,在打包時可以把密碼存為String物件,這樣會造成安全問題

如何打破雙親委派?

重寫loadclass方法

自定義載入器

我們自定義的類載入器只需要繼承ClassLoader,並覆蓋findClass方法