如果覺得寫的還可以請關(guān)注微信公眾號:程序猿的日常分享稠项,定期更新分享天揖。
JVM在加載類時默認采用的是雙親委派機制。通俗的講谓罗,就是某個特定的類加載器在接到加載類的請求時,首先將加載任務委托給父類加載器餐塘,依次遞歸妥衣,如果父類加載器可以完成類加載任務,就成功返回;只有父類加載器無法完成此加載任務時税手,才自己去加載蜂筹。關(guān)于虛擬機默認的雙親委派機制,我們可以從系統(tǒng)類加載器和標準擴展類加載器為例作簡單分析芦倒。
java自帶類加載器
類加載器負責加載所有的類艺挪,其為所有被載入內(nèi)存中的類生成一個java.lang.Class實例對象。一旦一個類被加載如JVM中兵扬,同一個類就不會被再次載入了麻裳。正如一個對象有一個唯一的標識一樣,一個載入JVM的類也有一個唯一的標識器钟。在Java中津坑,一個類用其全限定類名(包括包名和類名)作為標識;但在JVM中傲霸,一個類用其全限定類名和其類加載器作為其唯一標識疆瑰。
Bootstrap ClassLoader
1、JVM自帶的引導類加載器昙啄,由C/C++的語言實現(xiàn)穆役,在Java中打印null;
2梳凛、加載Java的核心類庫耿币,$JAVA_HOME中jre/lib/rt.jar、resource.jar或Java程序運行指定的Xbootclasspath選項jar包韧拒;
3淹接、指定加載java,javax叭莫,sun等開頭的包類名蹈集。
如果自定義了一個類,這個類的包名為java.lang雇初,那么new一個這個自定義類的對象就會報錯拢肆,因為java開頭的包類名不能自定義類!
Extension ClassLoader
1靖诗、Java語言編寫的類加載器sun.misc.Launcher$ExtClassLoader(靜態(tài)內(nèi)部類)
2郭怪、指定Bootstrap ClassLoader為Parent加載器-->getParent()可以獲取Bootstrap ClassLoader
3、負責加載java平臺中擴展功能的一些jar包刊橘,包括$JAVA_HOME中jre/lib/ext或-Djava.ext.dirs指定目錄下的jar包(如果我們自定義的class需要交給Ext來加載可以放置到ext的目錄下)
Application ClassLoader
1鄙才、Java語言編寫的類加載器sun.misc.Launcher$APPClassLoader(靜態(tài)內(nèi)部類)
2、該加載器是Java程序默認的類加載器促绵,Java應用的類都是該類加載器加載的
3攒庵、指定Extension ClassLoader為parent加載器-->getParent()可以獲取Extension ClassLoader
4嘴纺、負責加載環(huán)境變量classpath指定的目錄,或者java.class.path指定的目錄類庫
自定義類加載器
自定義類加載器的工作流程:
1浓冒、首先檢查請求的類型是否已經(jīng)被這個類裝載器裝載到命名空間中了栽渴,如果已經(jīng)裝載,直接返回稳懒;否則轉(zhuǎn)入步驟2
2闲擦、委派類加載請求給父類加載器(更準確的說應該是雙親類加載器,真?zhèn)€虛擬機中各種類加載器最終會呈現(xiàn)樹狀結(jié)構(gòu))场梆,如果父類加載器能夠完成墅冷,則返回父類加載器加載的Class實例;否則轉(zhuǎn)入步驟3
3或油、調(diào)用本類加載器的findClass(…)方法寞忿,試圖獲取對應的字節(jié)碼,如果獲取的到顶岸,則調(diào)用defineClass(…)導入類型到方法區(qū)罐脊;如果獲取不到對應的字節(jié)碼或者其他原因失敗,返回異常給loadClass(…)蜕琴, loadClass(…)轉(zhuǎn)拋異常,終止加載過程(注意:這里的異常種類不止一種)宵溅。
雙親委派機制
如果一個類加載器收到了類加載請求凌简,它不會首先加載這個類,而是將請求委派給父類加載器去完成恃逻,所有的加載請求最終都委派給頂層的引導類加載器雏搂,只有當父類加載器無法完成加載請求(也就是搜索范圍內(nèi)無該類),子加載器才會嘗試自己去加載這個類寇损。雙親委派模型如下:
雙親委派的流程是在接收到類加載請求后凸郑,首先從加載器緩存中查找,如果找到就直接返回結(jié)果矛市,如果沒找到則交給父類加載器加載芙沥,依次向上執(zhí)行,直到最底層的BootstrapClassLoader浊吏。
如果BootstrapClassLoader沒在緩存中找到而昨,那么就交給ExtClassLoader來加載,如果在加載器負責的范圍內(nèi)沒找到無法加載找田,則交給子加載器加載歌憨,依次向下執(zhí)行,直到自定義類加載器墩衙,如果自定義類加載器也無法執(zhí)行务嫡,則拋出ClassNotFoundException甲抖。流程如下:
雙親委派機器的好處
采用雙親委派模式的是好處是Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級的層次關(guān)系,通過這種層級關(guān)可以避免類的重復加載心铃,當父親已經(jīng)加載了該類時准谚,就沒有必要子ClassLoader再加載一次。
其次是考慮到安全因素于个,java核心api中定義類型不會被隨意替換氛魁,假設(shè)自定義了一個java.lang.String,并由自定義類加載器加載厅篓,并打包成java的類庫秀存,讓別人引用。那么如果在系統(tǒng)中密碼通常使用String羽氮,并且使用了我們提供的自定義String的類庫或链,那么我們就可以在自定義的String中把密碼發(fā)送給我們自己,所以雙親委派最重要的就是安全方面档押。
執(zhí)行模式
jvm有3種執(zhí)行模式分別是:混合執(zhí)行澳盐,編譯執(zhí)行,解釋執(zhí)行令宿。我們可以通過設(shè)置jvm的參數(shù)來指定執(zhí)行模式:
-Xmixed 默認為混合模式叼耙。開始是解釋執(zhí)行,過程中JIT對熱點代碼進行檢測和編譯
-Xint 純解釋執(zhí)行模式(int為intepreter縮寫)粒没,啟動速度快筛婉,執(zhí)行稍慢
-Xcomp 純編譯模式(comp為compiler縮寫),啟動速度慢癞松,執(zhí)行很快
-XX:CompileThreshold=10000 檢測熱點代碼爽撒,適用于混合模式