您好,登錄后才能下訂單哦!
JVM類的運行機制是什么?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
1.一段java程序是如何運行起來的呢?
Java源文件,通過編譯器,產生.Class字節碼文件,字節碼文件通過Java虛擬機中的解釋器,編譯成特定及其上的機器碼,那Java虛擬機又是怎樣加載java程序并執行起來的呢?
簡單來說:通過類加載器加載字節碼文件,被分配到JVM的運行時數據區的字節碼會被執行引擎執行。
(1)類加載器,加載.class文件
(2)運行數據區:棧區、堆區、PC寄存器、本地方法棧、方法區
(3)執行引擎:執行包在裝載類方法中的指令
2. 類加載器
類的加載是指將類的.class文件讀入內存,將其放在方法區內,然后在堆區創建一個java.lang.Class對象,用來封裝類在方法區內的數據結構,并向java程序員提供訪問方法區內數據結構的接口。類加載器并不需要等到某個類被首次主動使用時再加載它,JVM允許類加載器在預料某個類將要被使用時就預先加載它。
類的生命周期
類加載過程包括:加載、驗證、準備、解析、初始化
(1)加載:查找并加載類的二進制數據。
a. 通過一個類的全限定名來獲取其定義的二進制字節流
b. 將這個字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構
c. 在Java堆中生成一個代表這個類的java.lang.Class,作為對方法區中這些數據的訪問入口
(2)連接:
a. 驗證:確保被加載類的正確性
b. 準備:為類的靜態變量分配內存,并將其初始化為默認值
c. 解析:把類中的符號引用轉換為直接引用
(3)初始化:為類的靜態變量賦予正確的初始值
類加載器
啟動類加載器:BootstrapClassLoader,負責加載存放在JDK\jre\lib或被-Xbootclasspath參數指定的路徑中的,并且能被虛擬機識別的類庫。
擴展類加載器:ExtensionClassLoader,負責加載DK\jre\lib\ext目錄中,或者由java.ext.dirs系統變量指定的路徑中的所有類庫。
引用程序類加載器:ApplicationClassLoader,負責加載用戶路徑ClassPath所指定的類
JVM類加載機制
全盤負責:當一個類加載器負責加載某個Class時,該Class所依賴的和引用的其他Class也將由該類加載器負責載入,除非顯示使用另外一個類加載器來載入
父類委托:先讓父類加載器駛入加載該類,只有在父類加載器無法加載該類時才嘗試從自己的類路徑中加載該類
緩存機制:保證所有加載過的類都會被緩存,當需要使用某個類時,先從緩存區尋找該Class,只有緩存區不存在該類時,才會去加載此類。
雙親委派機制
意義:系統類防止內存出出現多分同樣的字節碼;保證Java程序安全穩定運行
(1)當AppClassLoader去加載一個class時,它首先不會自己去加載這個類,而是把類加載請求委派給父類加載器ExtClassLoader去完成。
(2)當ExtClassLoader去加載一個class時,它首先也不會自己去加載這個類,而是把類加載請求委派給BootStrapClassLoader去完成。
(3)如果BootStrapClassLoader加載失敗,會使用ExtClassLoader來嘗試加載。
(4)如果ExtClassLoader加載失敗,會使用AppClassLoader來加載
(5)如果AppClassLoader也加載失敗,則會爆出異常ClassNotFoundException
3. 運行數據區
(1)虛擬機棧:每個線程有一個私有的棧,隨著線程的創建而創建。棧里面存著一種叫“棧幀”的東東,每個方法會創建一個棧幀,棧幀中存放局部變量表(基本數據類型和對象飲用)、操作數棧、方法出口等信息,棧的大小可以固定也可以擴展,當棧調用深度大于JVM所允許的范圍,會拋出StackOverFlowError。
(2)本地方法棧:主要與虛擬機用到的native方法相關,java程序員不太關心。
(3)PC寄存器:也叫程序計數器。JVM支持多線程運行,每個線程都有自己的程序計數器。若當前執行的是JVM的方法,則該寄存器中保存當前執行指令的地址,若執行native方法,則為空。
(4)堆:堆內存是JVM所有線程共享的部分,虛擬機啟動時就已經創建。所有對象和數組都在堆上進行分配。這部分空間可通過GC進行回收,當申請不到空間時會拋出OutOfMemoryError。
(5)方法區:所有線程共享。主要用于存儲類的信息,常量池,方法數據,方法代碼等。
4. 執行引擎
方法調用會導致棧幀的入棧,會確定調用哪一個方法。
(1)棧幀。程序的執行對應著棧幀的入棧和出棧,棧幀主要包括:局部變量表、操作數棧、動態連接、方法返回地址等。
(2)方法調用。
解析調用:類加載的解析階段,會將其中一部分符號引用轉化為直接引用,這種解析的前提是方法在程序真正運行之前就有一個可確定的調用版本。編譯期可確定調用方法的版本:靜態方法、私有方法、實例構造器、父類方法。
分派調用:
a. 靜態分派:發生在編譯階段。所有依賴于靜態類型來定位方法執行版本的分派動作成為靜態分派,典型方法是重載。javac編譯器根據參數的靜態類型決定使用哪個重載版本。
b. 動態分派:運行期根據實際類型確定方法執行版本。與方法重寫有密切關系。
c. 單分派和多分派:單分派是根據一個宗量對目標方法進行選擇,多分派是根據多于一個宗量對目標方法進行選擇。
(3)執行引擎需將字節碼轉換成可以直接被JVM執行的語言,可通過以下兩種方式轉換:
a. 解釋器:一條一條的讀取,解釋并且執行字節碼指令
b. 即時編譯器:執行引擎首先按照解釋執行的方式來執行,在合適的時候,即時編譯器把整段字節碼編譯成本地代碼。內置了JIT編譯器的JVM都會檢查方法的執行頻率,如果一個方法的執行頻率超過一個特定的值的話,那么這個方法就會被編譯成本地代碼。
關于JVM類的運行機制是什么問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。