【隨筆】JVM核心:JVM運行和類加載

前言

本篇博客將寫一點關於JVM的東西,涉及JVM運行時數據區、類加載的過程、類加載器、ClassLoader、雙親委派機制、自定義類加載器等,這些都是博主本身的一點理解,若是有誤,歡迎你們評論拍磚~java

關於JVM運行時數據區

【隨筆】JVM核心:JVM運行和類加載

關於類加載

class文件加載至內存,連接(校驗、解析),初始化;最終造成JVM能夠直接使用的JAVA類型的過程。bootstrap

加載:在方法區造成類的運行時數據結構;在堆裏面造成該類的Class對象,做爲訪問方法區的入口。

【隨筆】JVM核心:JVM運行和類加載數組

連接:class文件是否存在問題;一些符號引號替換成直接引用。

初始化:初始化一個類,先初始化它的父類。虛擬機會保證一個類的初始化在多線程環境中被正確加鎖和同步。安全

要使用類A,必須先加載類A;加載類A,就會把靜態變量、靜態塊合併初始化,而後在調用構造器。注意類的加載和初始化,只有一次。服務器

關於類加載器

上文已經說了,類加載器的做用就是:將class文件的字節碼內容加載到內存中,並將這些靜態數據轉化成方法區中的運行時數據結構,在堆中生成一個表明這個類的Class對象,做爲方法區類數據的訪問入口。數據結構

類加載器的層次結構
多線程

引導類加載器bootstrap classloaderapp

加載JAVA核心庫($JAVA_HOME/jre/lib/rt.jar),原生代碼實現(C++),並不繼承自java.lang.ClassLoader。ide

擴展類加載器extensions classloaderspa

JAVA能夠提供一個擴展目錄($JAVA_HOME/jre/ext/*.jar)來加載Java類。

由sun.misc.Launcher.ExtClassLoader實現

應用程序類加載器application classloader(也稱系統類加載器)

通常來講,JAVA應用的類由它加載,即加載路徑是classpath下的路徑。

由sun.misc.Launcher.AppClassLoader實現。

自定義類加載器

開發人員繼承java.lang.ClassLoader實現本身的類加載器

【隨筆】JVM核心:JVM運行和類加載

關於java.lang.ClassLoader

ClassLoader的基本職責就是:

第一,根據指定的類名稱,找到或者生成對應的字節碼,並根據字節碼生成class對象

第二,加載JAVA應用所需的資源,如配置文件等。

ClassLoader的組合模式

【隨筆】JVM核心:JVM運行和類加載

【隨筆】JVM核心:JVM運行和類加載

引導類加載器是原生代碼實現,咱們獲取不到,因此是null。

ClassLoader重要API

getParent():該類加載器的父類加載器

loadClass(String name):加載名稱爲name的類,並返回Class實例。

加載順序是:先交給擴展類加載器加載,若是加載不到,交給引導類加載器加載,加載不到,交給本身去加載,若是本身也加載不到,那麼ClassNotFoundException。【雙親委派機制】 若是要改變類的加載順序,那麼能夠override該方法。

findClass(String name),不是加載,僅僅是查找而已

findLoadedClass(String name),查找已經被加載過的

defineClass(String name,byte[] b, int off ,int len),能夠把字節數組的內容轉換成JAVA類,並會返回Class實例。

類加載器的代理模式:雙親委派機制

類加載器的代理模式:就是把加載指定類的過程交給其餘加載器。

JAVA默認使用的類加載器代理模式是:雙親委派機制。

雙親委派機制:

就是某個特定的類加載器接到加載類的請求時,首先將加載任務委託給父類加載器,依次追溯,好比說從應用加載器委託給擴展類加載器,從擴展類加載器委託給引導類加載器。這種委託,直至委託到層次最高的類加載器,即引導類加載器,若是委託的父類加載器能夠完成加載任務,那麼成功返回;只有父類加載器沒法完成時,纔去本身加載。

能夠看出雙親委派機制的意思就是優先父類加載器加載!

試想若是咱們定義了一個java.lang.String類,根據雙親委派機制,那麼JDK只會加載它本身的String。這顯然保證了Java核心庫的類型安全。

雙親委派機制不是惟一的選擇

雖然JDK默認的類加載機制是雙親委派機制,可是並非全部都採用,好比有些服務器,如Tomcat,雖然也採用代理的方式加載,可是加載順序卻偏偏和雙親委派機制相反,它是首先嚐試加載這個類,只有加載不到的狀況下,纔去讓父類加載器代理加載。

爲何會這樣呢,不是說雙親委派很安全麼?

其實就是在安全,和靈活方面進行取捨!

寫一個自定義類加載器

MyClassLoader:

【隨筆】JVM核心:JVM運行和類加載

重寫findClass:

【隨筆】JVM核心:JVM運行和類加載

Test:

【隨筆】JVM核心:JVM運行和類加載

通常狀況下,自定義類加載器,須要繼承自ClassLoader。

首先來講,能夠檢查請求的類是否已經被自定義的類加載器加載;若是加載了,那麼直接返回;不然,那麼交給父類加載器,就是進行雙親委派;若是雙親委派也加載不到,那麼交給自定義類加載器進行「自定義的方式」來加載類。

另外,被2個不一樣的類加載加載的同一個類,JVM不會認爲是一個類。

相關文章
相關標籤/搜索