Java虛擬機類加載機制淺談

Java虛擬機類加載機制淺談

  Java語言是一種編譯後再經過解釋器執行的過程, 解釋器主要就是如何處理解釋Class文件的二進制字節流。JVM主要包含三大核心部分:運行時數據區,類加載器和執行引擎。
 
   虛擬機將描述類的數據從Class文件加載到內存,並對數據進行校驗、準備、解析和初始化,最終就會形成可以被虛擬機使用的Java類型,這就是一個虛擬機的類加載機制。Java中的類是動態加載的,只有在運行期間使用到該類的時候,纔會將該類加載到內存中,Java依賴於運行期動態加載和動態鏈接來實現類的動態使用。
 
   一個類的整個生命週期如下:
 
 
   加載,驗證,準備,初始化和卸載在開始的順序上是固定的,但是可以交叉進行。
 
   在Java中,對於類有且僅有四種情況會對類進行“初始化”。
 
   1)使用new關鍵字實例化對象的時候,讀取或設置一個類的靜態字段時候(除final修飾的static外),調用類的靜態方法時候,都只會初始化該靜態字段或者靜態方法所定義的類。
 
   2)使用reflect包對類進行放射調用的時候,如果類沒有進行初始化,則先要初始化該類
 
   3)當初始化一個類的時候,如果其父類沒有初始化過,則先要觸發其父類初始化。
 
   4)虛擬機啓動的時候,會初始化一個有main方法的主類。
 
   注意:通過子類引用父類靜態字段,只會初始化父類不會初始化子類;通過數組定義來引用類,也不會觸發該類的初始化;常量在編譯階段會存入調用類的常量池中,本質上沒有直接引用到定義常量的類,因此也不會觸發定義常量的類的初始化。
 
   一、類加載過程
 
   1、加載
 
   加載階段主要完成三件事,即通過一個類的全限定名來獲取定義此類的二進制字節流,將這個字節流所代表的靜態存儲結構轉化爲方法區的運行時數據結構,在Java堆中生成一個代表此類的Class對象,作爲訪問方法區這些數據的入口。這個加載過程主要就是靠類加載器實現的,這個過程可以由用戶自定義類的加載過程。
 
   2、驗證
 
   這個階段目的在於確保Class文件的字節流中包含信息符合當前虛擬機要求,不會危害虛擬機自身安全。主要包括四種驗證:
 
   文件格式驗證:基於字節流驗證,驗證字節流是否符合Class文件格式的規範,並且能被當前虛擬機處理。
 
   元數據驗證:基於方法區的存儲結構驗證,對字節碼描述信息進行語義驗證。
 
   字節碼驗證:基於方法區的存儲結構驗證,進行數據流和控制流的驗證。
 
   符號引用驗證:基於方法區的存儲結構驗證,發生在解析中,是否可以將符號引用成功解析爲直接引用。
 
   3、準備
 
   僅僅爲類變量(即static修飾的字段變量)分配內存並且設置該類變量的初始值即零值,這裏不包含用final修飾的static,因爲final在編譯的時候就會分配了,同時這裏也不會爲實例變量分配初始化。類變量會分配在方法區中,而實例變量是會隨着對象一起分配到Java堆中。
 
   4、解析
 
   解析主要就是將常量池中的符號引用替換爲直接引用的過程。符號引用就是一組符號來描述目標,可以是任何字面量,而直接引用就是直接指向目標的指針、相對偏移量或一個間接定位到目標的句柄。有類或接口的解析,字段解析,類方法解析,接口方法解析。
 
   這裏要注意如果有一個同名字段同時出現在一個類的接口和父類中,那麼編譯器一般都會拒絕編譯。
 
   5、初始化
 
   初始化階段依舊是初始化類變量和其他資源,這裏將執行用戶的static字段和靜態語句塊的賦值操作。這個過程就是執行類構造器方法的過程。
 
   方法是由編譯器收集類中所有類變量的賦值動作和靜態語句塊的語句生成的,類構造器方法與實例構造器方法不同,這裏面不用顯示的調用父類的方法,父類的方法會自動先執行於子類的方法。即父類定義的靜態語句塊和靜態字段都要優先子類的變量賦值操作。
 
   二、類加載器
 
   1、類加載器的分類
 
   啓動類加載器(Bootstrap ClassLoader): 主要負責加載lib目錄中的,或是-Xbootclasspath參數指定的路徑中的,並且可以被虛擬機識別(僅僅按照文件名識別的)的類庫到虛擬機內存中。它加載的是System.getProperty("sun.boot.class.path")所指定的路徑或jar。
 
   擴展類類加載器(Extension ClassLoader):主要負責加載libext目錄中的,或者被java.ext.dirs系統變量所指定的路徑中的所有類庫。它加載的是託福答案
 
   System.getProperty("java.ext.dirs")所指定的路徑或jar。
 
   應用程序類加載器(Application ClassLoader):也叫系統類加載器,主要負責加載ClassPath路徑上的類庫,如果應用程序沒有自定義自己類加載器,則這個就是默認的類加載器。
 
   它加載的是System.getProperty("java.class.path")所指定的路徑或jar。
 
   2、類加載器的特點
 
   1)運行一個程序時,總是由Application Loader(系統類加載器)開始加載指定的類。
 
   2)在加載類時,每個類加載器會將加載任務上交給其父,如果其父找不到,再由自己去加載。
 
   3)Bootstrap Loader(啓動類加載器)是最頂級的類加載器了,其父加載器爲null.
 
   3、類加載器的雙親委派模型
 
   類加載器雙親委派模型的工作過程是:如果一個類加載器收到一個類加載的請求,它首先將這個請求委派給父類加載器去完成,每一個層次類加載器都是如此,則所有的類加載請求都會傳送到頂層的啓動類加載器,只有父加載器無法完成這個加載請求(即它的搜索範圍中沒有找到所要的類),子類才嘗試加載。
 
   下面是一個類加載器雙親委派模型,這裏各個類加載器並不是繼承關係,它們利用組合實現的父類與子類關係。
 
 
   4、類加載的幾種方式
 
   1)命令行啓動應用時候由JVM初始化加載,加載含有main的主類。
 
   2)通過Class.forName()方法動態加載類,默認會執行初始化塊。如果指定了ClassLoader,則不會執行初始化塊。
 
   3)通過ClassLoader.loadClass()方法動態加載類,不會執行初始化塊。
 
   5、類加載實例
 
   當在命令行下執行:java HelloWorld(HelloWorld是含有main方法的類的Class文件),JVM會將HelloWorld.class加載到內存中,並在堆中形成一個Class的對象HelloWorld.class。
 
   基本的加載流程如下:
 
   1)尋找jre目錄,尋找jvm.dll,並初始化JVM;
 
   2)產生一個Bootstrap Loader(啓動類加載器);
 
   3)Bootstrap Loader自動加載Extended Loader(標準擴展類加載器),並將其父Loader設爲BootstrapLoader。
 
   4)Bootstrap Loader自動加載AppClass Loader(系統類加載器),並將其父Loader設爲ExtendedLoader。
 
   5)最後由AppClass Loader加載HelloWorld類。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章