java虚拟机类加载机制浅谈_浅谈Java虚拟机(三)之类加载机制
在《淺談Java虛擬機》這篇文章中,我們提到了JVM從操作系統(tǒng)方面來說,可以將其看做是一個進程,分別有類加載器子系統(tǒng),執(zhí)行引擎子系統(tǒng)和垃圾收集子系統(tǒng)。這一篇文章就簡單的來談一下類加載器子系統(tǒng)中的類加載機制。
第一:什么叫做類加載機制
就是JVM把.class字節(jié)碼文件加載到內(nèi)存中,并對其數(shù)據(jù)進行校驗、準備、解析和初始化,最終形成能夠被JVM可以直接拿來使用的java類型的一個過程,叫做類加載。如圖示:
1:加載
(1)將.class字節(jié)碼文件加載到內(nèi)存中
(2)將靜態(tài)數(shù)據(jù)結(jié)構(gòu)(即數(shù)據(jù)存在于.class字節(jié)碼文件的結(jié)構(gòu))轉(zhuǎn)化為方法區(qū)(詳見《淺談Java虛擬機(二)》)中運行時的數(shù)據(jù)結(jié)構(gòu)(即數(shù)據(jù)存在于JVM時的數(shù)據(jù)結(jié)構(gòu))
(3)在堆中生成一個代表這個類的java.lang.Class對象,作為數(shù)據(jù)訪問的入口
(4)有一些類是已經(jīng)提前就被加載到了JVM中的,無需等到運行加載時才加載
2:連接
連接就是講java類的二進制代碼合并到java的運行狀態(tài)的過程
(1)驗證:確保加載的類符合JVM的規(guī)范與安全
(2)準備:為static變量在方法區(qū)中分配空間,設(shè)置變量的初始值。例如 static int a = 6,在此階段會將a被初始化為0。(此處特別注意:如果是 static final int a = 6,那么會在此階段將a的值初始化為6)
(3)解析:JVM將常量池中的符號引用轉(zhuǎn)化為直接引用。例如 "abc"為常量池中的一個值,直接會將"abc"替換成存在于內(nèi)存中的地址。
1)符號引用:符號引用與虛擬機實現(xiàn)的內(nèi)存布局無關(guān),引用的目標并不一定已經(jīng)加載到內(nèi)存中。它是以一組符號來描述所引用的目標,符號可以是任何形式的字面量,只要使用時能無歧義的定位到目標即可。
2)直接引用:直接引用可以是直接指向目標的指針、相對偏移量或是一個能間接定位到目標的句柄。直接引用是與虛擬機實現(xiàn)的內(nèi)存布局相關(guān)的,如果有了直接引用,那么引用的目標必定已經(jīng)在內(nèi)存中存在。
3:初始化
初始化階段是類加載最后一個階段,前面的類加載階段之后,除了在加載階段可以自定義類加載器以外,其它操作都由JVM主導。到了初始階段,才開始真正執(zhí)行類中定義的Java程序代碼。
初始化階段是執(zhí)行類構(gòu)造器方法的過程,方法是由編譯器自動收集類中的類變量的賦值操作和靜態(tài)語句塊中的語句合并而成的。虛擬機會保證方法執(zhí)行之前,父類的方法已經(jīng)執(zhí)行完畢。
4:使用--- 正常使用
5:卸載 ---GC把無用對象從內(nèi)存中卸載
第二:類加載與初始化時機
1:類加載時機
當應用程序啟動的時候,因為內(nèi)存資源有限,為避免影響應用程序的正常運行,所有的類是不會被一次性加載的。
當User user = new User()的時候,一個類真正被加載的時機是在創(chuàng)建對象的時候,才會去執(zhí)行以上的五個過程,去加載類。大家都知道,java中的main方法是程序的入口,所以它最先加載的是擁有main方法的主線程的所在類。
2:類初始化時機
(1)主動引用(有類初始化過程)
1)new 一個對象。
2)調(diào)用類的靜態(tài)成員(除了final常量)和靜態(tài)方法
3)通過反射(reflect)對類進行調(diào)用
4) JVM啟動,main方法鎖在類被提前初始化
5)初始化一個類,如果其父類沒有被初始化,則先初始化父類
(2)被動引用(沒有類初始化過程)
1)當訪問一個靜態(tài)變量時,只有真正聲明這個變量的類才會被初始化
2)通過數(shù)組定義類的引用
3)final變量不會觸發(fā)此類的初始化,因為在其編譯階段就會存儲在常量池中
第三:類加載器
虛擬機設(shè)計團隊把加載動作放到JVM外部實現(xiàn),以便讓應用程序決定如何獲取所需的類,JVM提供了3種類加載器:
(1)啟動類加載器(Bootstrap ClassLoader):
負責加載 JAVA_HOME\lib 目錄中的,或通過-Xbootclasspath參數(shù)指定路徑中的,且被虛擬機認可(按文件名識別,如rt.jar)的類
(2)擴展類加載器(Extension ClassLoader):
負責加載 JAVA_HOME\lib\ext 目錄中的,或通過java.ext.dirs系統(tǒng)變量指定路徑中的類庫
(3)應用程序類加載器(Application ClassLoader):
負責加載用戶路徑(classpath)上的類庫
JVM通過雙親委派模型進行類的加載,當然我們也可以通過繼承java.lang.ClassLoader實現(xiàn)自定義的類加載器。
當一個類加載器收到類加載任務,會先交給其父類加載器去完成,因此最終加載任務都會傳遞到頂層的啟動類加載器,只有當父類加載器無法完成加載任務時,才會嘗試執(zhí)行加載任務。
采用雙親委派的一個好處是比如加載位于rt.jar包中的類java.lang.Object,不管是哪個加載器加載這個類,最終都是委托給頂層的啟動類加載器進行加載,這樣就保證了使用不同的類加載器最終得到的都是同樣一個Object對象。
jdk中的ClassLoader的源碼實現(xiàn):protected synchronized Class> loadClass(String name,boolean resolve)throws ClassNotFoundException {// First, check if the class has already been loadedClass c = findLoadedClass(name);if (c ==null) {try {if (parent !=null) {c = parent.loadClass(name,false);}else {c = findBootstrapClass0(name);}}catch (ClassNotFoundException e) {// If still not found, then invoke findClass in order// to find the class.c = findClass(name);}2018-06-01 11:38
總結(jié)
以上是生活随笔為你收集整理的java虚拟机类加载机制浅谈_浅谈Java虚拟机(三)之类加载机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: !KMP算法完整教程
- 下一篇: java 基础面试 英文_[Java面试