隔了好久終於把這篇文章補上了,最近在看《深入理解Java虛擬機器》,一本很不錯的書,必須值得一看。
由於本人對Java類的載入過程一直是一知半解,所以優先看了一下這章,在這裡,我跟大家分享一下,有理解不到位的地方還希望大家指出。 一、為什麼需要
我們都知道不管是什麼程式,都是通過我們能夠識別的語言轉變為機器可以識別的語言,才能夠實現我們想要做到的功能。目前,我們把這種轉換分為兩類,也就是編譯型語言和解釋型語言。
——————————————————————————————————
編譯型語言:程式在執行之前需要一個專門的編譯過程,把程式編譯成 為機器語言的檔案,運行時不需要重新翻譯,直接使用編譯的結果就行了。
解釋型語言:程式不需要編譯,程式在運行時才翻譯成機器語言,每執 行一次都要翻譯一次。
——————————————————————————————————
總之,編譯型語言就是提前翻譯好了,直接用就可以,而解釋型語言就是邊看邊翻譯。而Java語言是兩種形式的結合,它需要先提前編譯成.class檔案,然後再在運行時將.class檔案解釋為機器語言。而這個解釋的任務就交由jvm來處理,處理的第一步就是.class檔案的載入過程。 二、如何?
類載入機制主要有三大部分,載入、串連、初始化,串連又分為驗證、準備、解析。
註:載入、驗證、準備、初始化的順序是固定的,解析不一定在初始化之前也有可能在初始化之後。 1、載入
我們平常說的載入大多不是指的類載入機制,只是類載入機制中的第一步載入。在這個階段,JVM主要完成三件事:
定位:通過一個類的全限定名(包名與類名)來擷取定義此類的二進位位元組流(Class檔案)。而擷取的方式,可以通過jar包、war包、網路中擷取、JSP檔案產生等方式。
轉換:將這個位元組流所代表的靜態儲存結構轉化為方法區的運行時資料結構。這裡只是轉化了資料結構,並未合并資料。(方法區就是用來存放已被載入的類資訊,常量,靜態變數,編譯後的代碼的運行時記憶體地區)
入口:在記憶體中產生一個代表這個類的java.lang.Class對象,作為方法區這個類的各種資料的訪問入口。這個Class對象並沒有規定是在Java堆記憶體中,它比較特殊,雖為對象,但存放在方法區中。 2、串連 驗證
檔案格式:第一階段要驗證位元組流是否符合Class檔案格式的規範,並且能被目前的版本的虛擬機器處理。
中繼資料:第二階段是對位元組碼描述的資訊進行語義分析,以保證其描述的資訊符合Java語言的規範的要求。
位元組碼:第三階段是整個驗證過程中最複雜的一個階段,主要目的是通過資料流和控制流程分析,確定程式文法是否是合法的,符合邏輯的。在第二階段對中繼資料資訊中的資料類型做完校正後,這個階段將對類的方法體進行校正分析,保證被校正類的方法在運行時候不會做出對虛擬機器有危害的事情。
符號引用:最後一個階段的校正發生在虛擬機器將符號引用轉化為直接引用的時候,這個轉換動作發生在串連的第三階段–解析中發生,符號引用可以看做是對類自身以外的資訊進行匹配性校正。 準備
準備階段是正式為類變數 分配記憶體並設定變數初始值的階段,這些變數所使用的記憶體都將在方法區中進行分配,記住,只為類變數分配記憶體,不包括執行個體變數,執行個體變數將會在對象執行個體化時隨對象一起分配在java堆中。
例如static int a=3,在此階段會a為類變數被初始化為0,其他資料類型參考成員變數聲明。只有在初始化的時候才將a初始化為3。但是如果是final static int a =3,說明a是ConstantValue屬性,那麼在準備階段變數a就會被初始化為3。 解析
解析階段是虛擬機器將常量池內的符號引用替換為直接引用的過程,對同一個符號引用進行多次解析請求是很常見的事情,虛擬機器不會重新再解析而是通過緩衝去拿出解析的資料,但是invokedynamic指令除外,它會每次被解析都會被重新解析,解析動作主要針對類,介面,欄位,類方法,介面方法,方法類型,方法控制代碼和調用點限定符7類符號引用進行,
——————————————————————————————————
符號引用:符號引用以一組符號來描述所引用的目標,符號可以是任何形式的字面量,只要使用時能無歧義地定位到目標即可。符號引用與虛擬機器實現的記憶體布局無關,引用 的目標並不一定已經載入到記憶體中。
直接引用:直接引用可以是直接指向目標的指標、相對位移量或是一個能間接定位到目標的控制代碼。直接引用是與虛擬機器實現的記憶體布局相關的,如果有了直接引用,那麼引用的目標必定已經在記憶體中存在。 3、初始化
初始化階段是執行類構造器方法的過程。方法是由編譯器自動收集類中的類變數的賦值操作和靜態語句塊中的語句合并而成的。虛擬機器會保證方法執行之前,父類的方法已經執行完畢。p.s: 如果一個類中沒有對靜態變數賦值也沒有靜態語句塊,那麼編譯器可以不為這個類產生()方法。 三、整體流程
總結:
jvm中類載入的過程就分為這三步,載入、串連(驗准解)、初始化 ,而對於初始化的時機和載入器什麼的都沒有提到,也就留到下次再說吧。希望大家能夠持續關注。