1. 程式人生 > >虛擬機器類載入機制

虛擬機器類載入機制

虛擬機器的類載入機制:虛擬機器把描述類的資料從Class檔案載入到記憶體,並對資料進行校驗、轉換解析和初始化,最終形成可以被虛擬機器直接使用的Java型別。

1.以下所說的“類”包括了類和介面,需要區分會特別說明

2.以下所說的“Class檔案”不是指在磁碟中的某個class檔案,是指一段二進位制流,無論以何種形式存在都可以

類的生命週期:載入->驗證->準備->解析->初始化->使用->解除安裝,紅色字型的3部分也統稱為連線

載入->驗證->準備->    ->初始化->   ->解除安裝,這5個步驟是依次開始(注意不一定是要完成前一步驟才能開始下一步驟)

載入:P214

“載入”是“類載入”過程的一個階段,在載入階段虛擬機器需要完成以下3件事情:

1)通過一個類的全限定名來獲取定義此類的二進位制位元組流(注意二進位制位元組流可以從除了Class檔案以外,其他比如ZIP、網路等地方獲取,這也是JAR、EAR、WAR格式的基礎)

2)將這個位元組流所代表的靜態儲存結構轉化為方法區的執行時資料結構

3)在記憶體中生成一個代表這個類的java.lang.Class物件,作為方法區這個類的各種資料的訪問入口

驗證:P216

驗證的目的是為了確保Class檔案的位元組流中包含的資訊符合當前虛擬機器的要求,並且不會危害虛擬機器自身的安全。(Java語言本身是相對於C/C++是安全的,但是虛擬機器執行的是Class的二進位制流,而前面的部落格說到過這個二進位制流不一定由Java語言編譯而來,也可能甚至是自己用十六進位制編輯器編寫出來。)

驗證階段大致會完成分為以下4個階段的檢驗動作:

1.檔案格式驗證:驗證位元組流是否符合Class檔案格式的規範,並能被當前版本的虛擬機器處理。

2.元資料驗證:對位元組碼描述的資訊進行語義分析,以保證其描述的資訊符合Java語言規範。(對資料型別進行校驗)

3.位元組碼驗證:通過資料流和控制流分析,確定程式語義是合法的、符合邏輯的,這是最複雜的一個階段。(對類的方法體進行校驗)

4.符號引用驗證:發生在虛擬機器將符號引用轉化為直接引用的時候,可以看做是類自身以外的資訊進行匹配性校驗。

準備:P219

準備階段是正式為類變數分配記憶體並設定類變數初始值的階段,這些變數所使用的記憶體都將在方法區中進行分配。(注意僅指的是類變數(被static修飾的變數),另外變數初始值不是初始化,比如 public static int value = 123;,這時是設定 value 的初始值為0,當然常量(final)是直接初始化的,程式碼設定多少就是多少)

解析:P220

解析階段是虛擬機器將常量池內的符號引用轉化為直接引用的過程。

        符號引用是指CONSTANT_Class_info之類的常量所代引用的目標(在《解析Class檔案的資料結構》中簡寫成Class_info)。

        直接引用是指直接指向目標的指標、相對偏移量或一個能間接定位到目標的控制代碼。

對符號引用的解析既可以發生在類被載入器載入時,也可以是等到符號引用被使用前進行解析。

解析動作主要針對類或介面、欄位、類方法、介面方法、方法型別、方法控制代碼和呼叫點限定符7類符號引用進行。P221

初始化:P225

類初始化階段是類載入過程的最後一步,是真正開始執行類鍾定義的Java程式程式碼(或者說是位元組碼)

類與類載入器 P227

對於任意一個類,都需要由載入它的類載入器和這個類本身一同確定其在Java虛擬機器中的唯一性,每一個類載入器,都擁有一個獨立的類名稱空間。(這意味著由不同類載入器載入的同一個來自Class檔案產生的是兩個不相等的類,即便它們類的程式碼是一樣的)

從虛擬機器的角度:兩種不同的類載入器

         一是啟動類載入器(對於HotSpot虛擬機器而言是由C++實現的),是虛擬機器自身自帶的類載入器(意味著無法被程式直接引用)

        二是其他的類載入器,又細分為擴充套件類載入器和應用程式類載入器(別名系統類載入器)

雙親委派模型 P231

雙親委派模型除了頂層啟動類載入器外,其餘類載入器都應有自己的父類載入器,但是一般不會以繼承關係實現,而是使用組合關係來複用父載入器的程式碼。

工作流程:當一個類收到類載入請求,它首先會委派給父類載入,當父類無法載入這個類時才會由子類嘗試載入。(這意味著類載入器具備一種帶有優先順序的層次關係,例如 java.lang裡的類,無論是哪一個類載入器載入,最終還是由頂層的啟動類載入器載入,從而避免了java基礎類會產生兩個不同的類(前面提到的必須由同一個類載入器載入的同一個Class檔案才能是同一個類))