java虚拟机类加载机制_《深入理解java虚拟机》学习笔记一/类加载机制
為何要讀這本書?
近期看了左蕭龍大哥的單例設計模式,后文講解到了JVM對類實例化相關知識,感覺看著很無力,不懂,于是乎買本書研究下。
如何讀?
個人水平一般,理解程度有限,書中說到每章關聯不是很大,所以就以目前想了解的內容讀起。
本系列筆記會隨著個人的理解深度隨時更新,記錄在這里算是一個總結吧。
本篇學習類加載機制。
代碼編譯結果,本地機器碼轉換為字節碼。 虛擬機如何加載class文件? class文件的信息進入虛擬機會發生什么樣的變化?
類加載機制: 虛擬機把描述類的文件從class文件加載進內存,并對數據進行校驗,轉換解析和初始化,最終形成可以被虛擬機識別的java類型。 java中類型的加載、連接初始化過程都是在程序運行期間完成的。
類加載的時機: 加載、驗證、準備、
解析、初始化、使用、卸載 加載、驗證、準備、初始化、卸載這五個階段的順序是確定的,類的加載過程必須按照這種順序按部就班地執行。
解析不一定,有的時候可以在初始化之后執行,這是為了支持java語言的運行時綁定(動態綁定、晚期綁定)
什么時候開始類加載的第一個階段:加載? java虛擬機規范中沒有強行約束,但是對于初始化階段,虛擬機規范中嚴格要求有且只有五種情況必須立即對類進行”初始化”(而加載、驗證、準備要在此之前開始): 1、遇到new、getstatic、putstatic、invokestatic這四條字節碼指令時,如果類沒有初始化,需要先觸發其初始化。 觸發場景: new對象 讀取或設置一個類的靜態字段(被final修飾) 調用一個類的靜態方法時 2、使用java.lang.reflect包的方法對類進行反射調用的時候,如果類沒有初始化,需要首先對其初始化。 3、當初始化一個類的時候,其父類還沒有進行初始化,需要先初始化其父類 4、虛擬機啟動時,用戶需要指定一個要執行的主類(包含main()方法的那個類),虛擬機會先初始化這個主類 5、當使用jdk1.7的動態語言支持時,如果一個java.lang.invoke.MethodHandle實例最后的解析結果為REF_getStatic、REF_putStatic 、REF_invokeStatic 的方法句柄,并且這個方法句柄所對應的類沒有進行初始化,則需要先觸發其初始化。
上述五種情況稱為對一個類的主動引用,此外所有引用類的方式都不會觸發初始化,稱為
被動引用 被動引用例子一發現: 對于靜態字段,只有直接定義這個字段的類才會被初始化,至于是否要觸發子類的加載和驗證,虛擬機規范中并未明確。 被動引用例子二發現: 通過數組定義來引用類,不會觸發此類的初始化 被動引用例子三發現: 常量在編譯階段會存入調用類的常量池中,本質上沒有直接引用到定義常量的類,因此就不會觸發定義常量的類的初始化,也就是說這倆個類在編譯成class文件后就沒有任何關系了
類加載過程詳解:
加載 加載是類加載過程的一個階段 在加載階段,虛擬機需要完成的三件事: 1、通過一個類的全限定名來獲取定義此類的二進制字節流 2、將這個字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構 3、在內存中生成一個代表此類的java.lang.Class對象,作為方法區這個類的各種數據的訪問入口 加載完成之后,虛擬機將外部的二進制字節流就按照虛擬機所需要的格式存儲在方法區之中,方法區中的數據存儲格式由虛擬機自行定義,虛擬機規范并未規定此區域的具體數據結構。然后在內存中實例化一個java.lang.Class類的對象(并沒有明確規定是在java堆中),這個對象將作為程序訪問方法區中的這些類型數據的外部接口。 加載階段與連接階段的部分內容(如一部分字節碼文件格式的驗證動作)是交叉進行的,加載階段尚未完成,連接階段可能已經開始,但這些夾在加載階段之中進行的動作,仍然屬于連接階段的內容,這倆個階段的開始時間仍然保持著固定的先后順序。
驗證 驗證是連接階段的第一步,這一階段的目的是為了確保Class文件的字節流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機的自身安全。 Class文件并不一定是java源碼編譯而來,虛擬機如果不檢查輸入的字節流,對其完全信任,很可能因為載入有害的字節流而導致系統崩潰,所以驗證是虛擬機對自身保護的一項重要工作。 詳見《Java虛擬機規范》,請自行搜索。 驗證階段會完成下面四個階段的驗證動作: 1、文件格式驗證 驗證內容:主要驗證字節流是否符合Class文件格式的規范,并且是否能被當前版本的虛擬機處理 驗證目的:確保輸入的字節流能正確地解析并存儲于方法區之內,格式上符合一個Java類型信息的要求。 這個階段的驗證是基于二進制字節流進行的,只有通過了這個階段的驗證后,字節流才會進入內存的方法區進行存儲,所以后面的三個驗證階段全部是基于方法區的存儲結構進行的,不會再直接操作字節流。 2、元數據驗證 驗證內容:對字節碼描述的信息進行語義分析,以保證其描述的信息符合java語言規范的要求。 驗證目的:對類的元數據信息進行語義校驗,保證不存在不符合java語言規范的元數據信息。 3、字節碼驗證 驗證內容:通過數據流和控制流分析,確定程序語義是合法的,符合邏輯的,在第二階段對元數據信息中的數據類型做完校驗后,這個階段將對類的方法體進行校驗分析,保證被校驗的方法在運行時不會做出危害虛擬機安全的事件 4、符號引用驗證 驗證內容:該階段的校驗發生在虛擬機將符號引用轉化為直接引用的時候,這個轉化動作將在連接的第三階段—解析階段發生。符號引用驗證可以看作是對類自身以外(常量池中的各種符號引用)的信息進行匹配校驗。 驗證目的:卻保解析動作能正常執行 可以使用-Xverify:none參數來關閉大部分的類驗證措施,以縮短虛擬機類加載的時間。
準備 準備階段是正式為類變量
分配內存并設置類變量的
初始值的階段,這些變量所使用的內存都將在方法區中進行分配。
需要注意的點: 這時候進行
內存分配的僅包括類變量(被static修飾的變量),而不包括實例變量,實例變量將會在對象實例化時候隨著對象一起分配在java堆內存中。
通常情況下初始值是數據類型的零值 如:public static int value = 110; 那么變量value在準備階段過后的值為0,而不是110,因為這時尚未執行任何java方法,而把value賦值為110的指令putstatic是在程序被編譯后,存放于類構造器()方法中。所以將value賦值為110的動作將在初始化階段才會執行。
特殊情況下 如果類字段的字段屬性表中存在ConstantVlaue屬性,那么在準備階段value就會被初始化為ConstantValue屬性所指定的值 如:public static
final int value = 110; 編譯時javac將會為value生成ConstantValue屬性,在準備階段虛擬機就會根據ConstantValue的設置將value賦值為110
解析 解析階段是虛擬機將常量池內的符號引用替換為直接引用的過程。
初始化
使用
卸載
總結
以上是生活随笔為你收集整理的java虚拟机类加载机制_《深入理解java虚拟机》学习笔记一/类加载机制的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: java遍历本地文件夹_JAVA遍历一个
- 下一篇: java 解密 php_使用JAVA解密
