Java虛擬機經過裝載、鏈接和初始化一個Java類型,使該類型能夠被正在運行的Java程序所使用。其中裝載就是把二進制形式的Java class文件讀入Java虛擬機中去;鏈接把讀入虛擬機的二進制形式的Java class文件合併到虛擬機的運行時的狀態中去。鏈接能夠分爲三個子步驟,驗證,準備和初始化。驗證步驟確保了Java類型數據格式正確而且適於Java虛擬機使用。準備爲該類型分配內存(如爲類變量分配內存)。解析負責將常量池中的符合引用轉換爲直接引用,虛擬機的實現能夠推遲解析這一步驟。即當運行中的程序真正使用某個符號的時候再去解析它。(符號引用變爲直接引用)。初始化爲類變量賦以適當的初始值。
下面就這5個步驟進行詳細的解析:java
裝載階段由三個動做完成程序員
裝載的最終目的就是建立java.lang.class的實例對象,解析二進制數據流爲方法區的內部數據結構,並在堆上面創建一個Class對象。Class對象是Java程序與內部數據結構之間的接口。數據庫
Java類型要麼被啓動類裝載器裝載,要麼被用戶自定義的類加載器加載。
類加載器並非在某個類型首次主動使用的時候加載它。能夠提早預判,預加載這個類型。若是預加載的時候出現問題,不會當即報錯。直到程序主動使用該類才報錯。也就是說程序已知不主動使用該類類型,類加載器就一直不報錯。網絡
裝載時會作兩項檢查,雖然在驗證階段以前進行,但邏輯上屬於驗證階段。數據結構
類型被加載後,虛擬機開始鏈接,鏈接第一步是驗證,即確認它是否符合Java語言的語義,而且不會危及虛擬機的完整性。
驗證的時機和方式,不一樣虛擬機有着不一樣的實現。虛擬機規範只是規定了虛擬機在驗證過程當中能夠拋出的異常以及在何種狀況下必須拋出它們。
驗證階段每每會驗證以下內容:性能
上述任務最複雜的是最後一個,檢查字節碼的完整性。不能由於挑戰指令超出了方法末尾致使了虛擬機崩潰。虛擬機必須在驗證階段檢查出這樣的字節碼是非法的,從而拋出一個錯誤。
不過虛擬機規範並未規定字節碼驗證必須在驗證階段執行,也能夠在執行每條語句的時候單獨進行驗證。Java虛擬機指令集當初設定目標是字節碼流一次性使用數據流分析器進行驗證。不過運行時候進行驗證,會使得Java程序運行速度提升。當使用數據流分析器進行字節碼驗證時候,可能爲了確保符合Java語言的語義而裝載其餘的類。好比加載了Float類,必須還加載其父類Number保證其不是一個final類。.net
驗證階段以後可能還會進行一項檢查,那就是符號引用的驗證。虛擬機在將符號引用替換爲直接引用,須要檢查該元素的存在性以及訪問的權限。邏輯上屬於驗證,但每每在解析階段發生。指針
在準備階段,Java虛擬機爲類變量分配內存,並設置默認的初始值。在正式初始化階段以前,類變量都沒有被正式初始化爲真正的初始值。
準備階段,乾的另一件事就是可能爲一些數據結構分配內存,進而提升程序運行的性能。好比方法表的創建,它包含了指向類中每個方法包括從超類繼承方法的指針。從而能夠在執行繼承方法時候不須要搜索超類。對象
解析過程就是在類型的常量池中尋找類、接口、自動和方法的符合引用,把這些符號引用變成直接引用的過程。還記得邏輯上屬於驗證的符合引用的驗證麼?解析何時執行是虛擬機本身決定的,能夠在初始化階段後面執行。blog
初始化階段爲類變量賦予正確的初始值。在準備階段,類變量被賦予了默認值,在這一階段,類變量被賦予正確的初始值,即程序員但願這個類變量具有的起始值。
具體的初始化過程參見下一篇博客《淺談類加載的初始化階段》