“ 如果說核心類庫的 API 比做數學公式的話,那麼 Java 虛擬機的知識就好比公式的推導過程”
每本Java入門書籍在介紹Java這門語言的時候都會提到Java跨平臺,“一次解釋,到處運行的特點“,功臣就是jvm(Java Virtual Machine,Java虛擬機)。
但是,如果將jvm只與Java語言綁定在一起,那麼理解就過於狹隘了,Java虛擬機發展到現在已經脫離了Java語言,形成了一套相對獨立,高性能的執行方案。
除了以上提到的幾種語言之外,scala,熱門的kotlin都可以運行在jvm上面。
01 類生命週期
類從被加載到虛擬內存中開始,到卸載內存爲止,它的整個生命週期包括:
小提示:
1.加載階段和連接階段有時候是交叉進行的,不需要等到完全加載結束。
2. 解析階段有時候可以再初始化之後再做。Jvm僅僅規定了:如果某些字節碼使用了符號引用,那麼在執行這些字節碼之前,需要完成對這些符號引用的解析。
3. 但是這些過程總的開始時間和完成時間都是上圖固定順序。
4. 這裏的“加載階段”和我們常說的“類加載”是兩回事,“類加載”指的是虛線框中三部分加起來。
02 連接(Linking)
驗證:
當一個類被加載之後,必須要驗證一下這個類是否合法,比如這個類是不是符合字節碼的格式、變量與方法是不是有重複、數據類型是不是有效、繼承與實現是否合乎標準等等。
我們平常寫代碼很多時候第一步都是寫校驗,jvm也是這個思路,Java 編譯器生成的類文件必然滿足 Java 虛擬機的約束條件,但是爲了防止“解字節碼注入”。
準備:
-
就是爲類的靜態變量分配內存並設爲 jvm默認 的初值,而不是我們設置的,我們設置的會在後面一個階段“初始化”期間來做,對於非靜態的變量,則不會爲它們分配內存。
jvm默認的初值是這樣的:
基本類型(int、long、short、char、byte、boolean、float、double)的默認值爲0。其中boolean只有true,false兩種類型,對應到jvm值分別是數據1,0。
引用類型(對象,數組)的默認值爲null。
-
構造其他跟類層次相關的數據結構,比如說用來實現虛方法的動態綁定的方法表。
在 class 文件被加載至 Java虛擬機之前,這個類無法知道其他類及其方法、字段所對應的具體地址,甚至不知道自己方法、字段的地址。因此,每當需要引用這些成員時,Java 編譯器會生成一個符號引用。在運行階段,這個符號引用一般都能夠無歧義地定位到具體目標上。
解析:
上面說到的“在運行階段,這個符號引用一般都能夠無歧義地定位到具體目標上”,就是在解析階段進行的符號解析。
這個階段目的正是將常量池中的符號引用轉換解析成爲實際引用。在解析階段,jvm會將所有的類或接口名、字段名、方法名轉換爲具體的內存地址,從而讓用到了別的類或者接口的類能找到和加載其他的類/接口。
如果符號引用指向一個未被加載的類,或者未被加載類的字段或方法,那麼解析將觸發這個類的加載(但未必觸發這個類的鏈接以及初始化。)
03 初始化
在 Java 代碼中,如果要初始化一個靜態字段,我們可以在聲明時直接賦值,也可以在靜態代碼塊中對其賦值。除了final static修飾的常量,直接賦值操作以及所有靜態代碼塊中的代碼,則會被 Java 編譯器置於同一方法中,並把它命名爲 < clinit >。
類加載的最後一步是初始化,目的便是爲標記爲常量值的字段賦值,以及執行 <clinit > 方法的過程。Java 虛擬機會通過加鎖來確保類的 < clinit > 方法僅被執行一次。
類初始化的觸發情況:
-
當虛擬機啓動時,初始化用戶指定的主類(main函數);
-
當遇到用以新建目標類實例的 new 指令時,初始化 new 指令的目標類;
-
當遇到調用靜態方法的指令時,初始化該靜態方法所在的類;
-
當遇到訪問靜態字段的指令時,初始化該靜態字段所在的類;
-
子類的初始化會觸發父類的初始化;
-
如果一個接口定義了 default 方法,那麼直接實現或者間接實現該接口的類的初始化,會觸發該接口的初始化;
-
使用反射 API 對某個類進行反射調用時,初始化這個類;
-
當初次調用 MethodHandle 實例時,初始化該 MethodHandle 指向的方法所在的類。
設計模式中單例延遲加載,便是充分利用了這個特點。
04 卸載
那麼多的類,什麼時候卸載誰呢?關於卸載誰,滿足如下條件:
· 該類所有的實例都已經被回收,也就是java堆中不存在該類的任何實例;
· 加載該類的ClassLoader已經被回收;
· 該類對應的java.lang.Class對象沒有任何地方被引用,無法在任何地方通過反射訪問該類的方法。
關於什麼時候卸載,當以上條件都滿足了,垃圾回收時候回在方法區清空類信息進行卸載,英雄遲暮,這個類的一生也就走到了盡頭了。
有錯歡迎私我指正