类加载过程(加载+验证+准备+解析+初始化)
2019獨角獸企業重金招聘Python工程師標準>>>
????JVM把class文件加載的內存,并對數據進行校驗、轉換解析和初始化,最終形成JVM可以直接使用的Java類型的過程就是加載機制。
????類從被加載到虛擬機內存中開始,到卸載出內存為止,它的生命周期包括了:加載(Loading)、驗證(Verification)、準備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸載(Unloading)七個階段,其中驗證、準備、解析三個部分統稱鏈接。
????加載(裝載)、驗證、準備、初始化和卸載這五個階段順序是固定的,類的加載過程必須按照這種順序開始,而解析階段不一定;它在某些情況下可以在初始化之后再開始,這是為了運行時動態綁定特性。值得注意的是:這些階段通常都是互相交叉的混合式進行的,通常會在一個階段執行的過程中調用或激活另外一個階段。
加載+驗證+準備+解析+初始化
1、“加載”階段,虛擬機需要完成以下三件事情:
(1)通過一個類的權限定名來獲取定義此類的二進制字節流
(2)將這個字節流所代表的靜態存儲結構轉化為方法去的運行時數據結構
(3)在java堆中生成一個代表這個類的java.lang.Class對象,作為方法去這些數據的訪問入口。
2、驗證
(1)文件格式驗證--驗證class文件格式規范,例如:?class文件是否已魔術0xCAFEBABE開頭 ,?主、次版本號是否在當前虛擬機處理范圍之內等
(2)元數據驗證--這個階段是對字節碼描述的信息進行語義分析,以保證起描述的信息符合java語言規范要求。驗證點可能包括:這個類是否有父類(除了java.lang.Object之外,所有的類都應當有父類)、這個類是否繼承了不允許被繼承的類(被final修飾的)、如果這個類的父類是抽象類,是否實現了起父類或接口中要求實現的所有方法。
(3)字節碼驗證--進行數據流和控制流分析,這個階段對類的方法體進行校驗分析,這個階段的任務是保證被校驗類的方法在運行時不會做出危害虛擬機安全的行為.如:保證訪法體中的類型轉換有效,例如可以把一個子類對象賦值給父類數據類型,這是安全的,但不能把一個父類對象賦值給子類數據類型、保證跳轉命令不會跳轉到方法體以外的字節碼命令上。
(4)符號引用驗證--符號引用中通過字符串描述的全限定名是否能找到對應的類、符號引用類中的類,字段和方法的訪問性(private、protected、public、default)是否可被當前類訪問。
3、準備
準備階段是正式為類變量分配內存并設置變量初始值的階段,這些內存都將在方法去中進行分配。
注意:(1)進行內存分配的僅包括類變量(被static修飾的變量),而不包括實例變量,實例變量將會在對象實例化時隨著對象一起分配在java堆中
(2)初始值是指數據類型的零值,例如:
public static int value = 123;
那么變量value在準備階段過后的值是0,而不是123,因為這時候尚未開始執行任何java方法。
再看:public static final int value = 123;
final修飾的字段,子啊準備階段虛擬機就會根據賦值,value的值為123.
4、解析
解析階段是虛擬機將常量池內的符號引用替換為直接引用的過程
????符號引用:符號引用是一組符號來描述所引用的目標對象,符號可以是任何形式的字面量,只要使用時能無歧義地定位到目標即可。符號引用與虛擬機實現的內存布局無關,引用的目標對象并不一定已經加載到內存中。
????直接引用:直接引用可以是直接指向目標對象的指針、相對偏移量或是一個能間接定位到目標的句柄。直接引用是與虛擬機內存布局實現相關的,同一個符號引用在不同虛擬機實例上翻譯出來的直接引用一般不會相同,如果有了直接引用,那引用的目標必定已經在內存中存在。
????虛擬機規范并沒有規定解析階段發生的具體時間,只要求了在執行anewarry、checkcast、getfield、instanceof、invokeinterface、invokespecial、invokestatic、invokevirtual、multianewarray、new、putfield和putstatic這13個用于操作符號引用的字節碼指令之前,先對它們使用的符號引用進行解析,所以虛擬機實現會根據需要來判斷,到底是在類被加載器加載時就對常量池中的符號引用進行解析,還是等到一個符號引用將要被使用前才去解析它。
(1)類或接口的解析
(2)字段解析:首先解析出類的方法表的class_index項中索引的字段所屬的類或接口的符號引用,然后繼續搜索:
先在類本身中查找字段
再在類的實現的接口中查找字段
然后在類的父類中查找字段
否則,查找失敗
(3)類方法解析:首先解析出類的方法表的class_index項中索引的方法所屬的類或接口的符號引用,然后繼續搜索:
????類方法和接口方法符號引用的常量類型定義是分開的,如果在類方法表中發現class_index中索引的是個接口,直接報錯。
? ? 在類中遞歸查找是否有簡單名稱和描述符都與目標相匹配的方法,如果有直接返回
? ? 在類實現的父類中查找是否有簡單名稱和描述符都與目標相匹配的方法,如果有直接返回
? ? 在類實現的接口列表及他們的父接口中查找是否有簡單名稱和描述符都與目標相匹配的方法,如果有直接報錯
? ? 否則,查找失敗
(4)接口方法解析:首先解析出類的方法表的class_index項中索引的方法所屬的類或接口的符號引用。正好與接口相反。
5、初始化
初始化階段才真正開始執行類中定義的java程序代碼
初始化階段是執行類構造器<clinit>()方法的過程。在以下四種情況下初始化過程會被觸發執行:
1.遇到new、getstatic、putstatic或invokestatic這4條字節碼指令時,如果類沒有進行過初始化,則需先觸發其初始化。生成這4條指令的最常見的java代碼場景是:使用new關鍵字實例化對象、讀取或設置一個類的靜態字段(被final修飾、已在編譯器把結果放入常量池的靜態字段除外)的時候,以及調用類的靜態方法的時候。
2.使用java.lang.reflect包的方法對類進行反射調用的時候
3.當初始化一個類的時候,如果發現其父類還沒有進行過初始化、則需要先出發其父類的初始化
4.jvm啟動時,用戶指定一個執行的主類(包含main方法的那個類),虛擬機會先初始化這個類
在準備階段,變量已經賦過一次系統要求的初始值,二在初始階段,則是根據程序員通過程序制定的主觀計劃去初始化類變量和其他資源。
參考:http://blog.csdn.net/java2000_wl/article/details/8040633
轉載于:https://my.oschina.net/winHerson/blog/114180
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的类加载过程(加载+验证+准备+解析+初始化)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 移动端app设计指南
- 下一篇: 网络及网络配置问题