一、概述
網上有許多介紹jvm的文章和視訊,但大多枯燥、晦澀難懂,很難讓小白堅持下去;如果你是一個小白,不用擔心,在本文中,我們将從0到1,一步步地介紹JVM的基本概念和工作原理。無論你是想深入了解Java語言,還是準備參加Java開發的面試,這篇文章都将為你提供有用的知識和技能。讓我們一起開始這段有趣的旅程吧!
二、正文
類加載器
idea編譯後的.class檔案,通過類加載器将之加載到JVM記憶體中,并放在運作時資料區的方法區内,然後再建立相對應的java.lang.Class對象,用來封裝類在方法區内的資料結構。
類加載器種類
類加載器名稱 | 說明 |
Bootstrap ClassLoader 【啟動類加載器】 | 1、采用c/c++實作,嵌套在jvm内部 2、加載Java核心類庫(JAVA_HOME/jre/lib/rt.jar),用于提供JVM自身需要的類 3、無法直接通路 |
Extension ClassLoader 【擴充類加載器】 | 1、采用java語言編寫 2、加載(JAVA_HOME/jre/lib/ext)下類庫 3、父類加載器:啟動類加載器 |
Application ClassLoader【應用程式類加載器】 | 1、采用java語言編寫 2、加載“classpath”環境變量所指定的路徑中的類,可以了解為加載我們自己寫的Java代碼,以及我的導入的三方Jar包中的代碼 3、父類加載器:擴充類加載器 |
自定義類加載器 | 1、繼承ClassLoader類,可定制類的加載方式 |
類加載時采用了雙親委派模式,什麼是雙親委派模式
當一個類加載器收到類加載的請求時,自己不會立刻去加載這個類,而是把加載請求委派給父類加載器完成,父類加載器也會做相同的處理;當父加載器在自己的搜尋範圍内找不到需要加載的類時,子加載器才會嘗試自己去加載,最後如果任何一個加載器都找不到這個類時,就會抛出:ClassNotFoundException異常。
classloader源碼分析
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// 檢查一下指定名稱的類是否已經加載過,如果加載過了,就不需要再加載,直接傳回
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
// 如果該類沒有加載過,則判斷是否存在父類加載器;
// 如果存在父類加載器,則由父類加載器進行加載
// 遞歸調用,父類加載器會進行相同判斷處理
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去查找并加載
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
// 是否需要在加載時進行解析(根據入參指定)
if (resolve) {
resolveClass(c);
}
return c;
}
}
為什麼需要雙親委派模式
假如沒有雙親委派機制,此時使用者編寫一個和jdk自帶的一模一樣的類(比如:java.lang.Object),并放到了Classpath中,那麼應用程式類加載器就把這個當做Object加載到了記憶體中,進而造成不可預知的後果;而雙親委派機制先一路向上委托,啟動類加載器去找的時候,就把正确的Object加載到了記憶體中,後面再加載使用者編寫的Object類時,是不會加載運作的。
是以:JDK自帶類是無法被覆寫的,而引入第三方的JAR是可以自己定義相同的類來覆寫的。