JVM類運(yùn)行機(jī)制實(shí)現(xiàn)原理解析
1.一段java程序是如何運(yùn)行起來的呢?
Java源文件,通過編譯器,產(chǎn)生.Class字節(jié)碼文件,字節(jié)碼文件通過Java虛擬機(jī)中的解釋器,編譯成特定及其上的機(jī)器碼,那Java虛擬機(jī)又是怎樣加載java程序并執(zhí)行起來的呢?
簡單來說:通過類加載器加載字節(jié)碼文件,被分配到JVM的運(yùn)行時(shí)數(shù)據(jù)區(qū)的字節(jié)碼會(huì)被執(zhí)行引擎執(zhí)行。
(1)類加載器,加載.class文件
(2)運(yùn)行數(shù)據(jù)區(qū):棧區(qū)、堆區(qū)、PC寄存器、本地方法棧、方法區(qū)
(3)執(zhí)行引擎:執(zhí)行包在裝載類方法中的指令
2. 類加載器
類的加載是指將類的.class文件讀入內(nèi)存,將其放在方法區(qū)內(nèi),然后在堆區(qū)創(chuàng)建一個(gè)java.lang.Class對象,用來封裝類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu),并向java程序員提供訪問方法區(qū)內(nèi)數(shù)據(jù)結(jié)構(gòu)的接口。類加載器并不需要等到某個(gè)類被首次主動(dòng)使用時(shí)再加載它,JVM允許類加載器在預(yù)料某個(gè)類將要被使用時(shí)就預(yù)先加載它。
類的生命周期
類加載過程包括:加載、驗(yàn)證、準(zhǔn)備、解析、初始化
(1)加載:查找并加載類的二進(jìn)制數(shù)據(jù)。
a. 通過一個(gè)類的全限定名來獲取其定義的二進(jìn)制字節(jié)流
b. 將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)
c. 在Java堆中生成一個(gè)代表這個(gè)類的java.lang.Class,作為對方法區(qū)中這些數(shù)據(jù)的訪問入口
(2)連接:
a. 驗(yàn)證:確保被加載類的正確性
b. 準(zhǔn)備:為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默認(rèn)值
c. 解析:把類中的符號引用轉(zhuǎn)換為直接引用
(3)初始化:為類的靜態(tài)變量賦予正確的初始值
類加載器
啟動(dòng)類加載器:BootstrapClassLoader,負(fù)責(zé)加載存放在JDK\jre\lib或被-Xbootclasspath參數(shù)指定的路徑中的,并且能被虛擬機(jī)識(shí)別的類庫。
擴(kuò)展類加載器:ExtensionClassLoader,負(fù)責(zé)加載DK\jre\lib\ext目錄中,或者由java.ext.dirs系統(tǒng)變量指定的路徑中的所有類庫。
引用程序類加載器:ApplicationClassLoader,負(fù)責(zé)加載用戶路徑ClassPath所指定的類
JVM類加載機(jī)制
全盤負(fù)責(zé):當(dāng)一個(gè)類加載器負(fù)責(zé)加載某個(gè)Class時(shí),該Class所依賴的和引用的其他Class也將由該類加載器負(fù)責(zé)載入,除非顯示使用另外一個(gè)類加載器來載入
父類委托:先讓父類加載器駛?cè)爰虞d該類,只有在父類加載器無法加載該類時(shí)才嘗試從自己的類路徑中加載該類
緩存機(jī)制:保證所有加載過的類都會(huì)被緩存,當(dāng)需要使用某個(gè)類時(shí),先從緩存區(qū)尋找該Class,只有緩存區(qū)不存在該類時(shí),才會(huì)去加載此類。
雙親委派機(jī)制
意義:系統(tǒng)類防止內(nèi)存出出現(xiàn)多分同樣的字節(jié)碼;保證Java程序安全穩(wěn)定運(yùn)行
(1)當(dāng)AppClassLoader去加載一個(gè)class時(shí),它首先不會(huì)自己去加載這個(gè)類,而是把類加載請求委派給父類加載器ExtClassLoader去完成。
(2)當(dāng)ExtClassLoader去加載一個(gè)class時(shí),它首先也不會(huì)自己去加載這個(gè)類,而是把類加載請求委派給BootStrapClassLoader去完成。
(3)如果BootStrapClassLoader加載失敗,會(huì)使用ExtClassLoader來嘗試加載。
(4)如果ExtClassLoader加載失敗,會(huì)使用AppClassLoader來加載
(5)如果AppClassLoader也加載失敗,則會(huì)爆出異常ClassNotFoundException
3. 運(yùn)行數(shù)據(jù)區(qū)
(1)虛擬機(jī)棧:每個(gè)線程有一個(gè)私有的棧,隨著線程的創(chuàng)建而創(chuàng)建。棧里面存著一種叫“棧幀”的東東,每個(gè)方法會(huì)創(chuàng)建一個(gè)棧幀,棧幀中存放局部變量表(基本數(shù)據(jù)類型和對象飲用)、操作數(shù)棧、方法出口等信息,棧的大小可以固定也可以擴(kuò)展,當(dāng)棧調(diào)用深度大于JVM所允許的范圍,會(huì)拋出StackOverFlowError。
(2)本地方法棧:主要與虛擬機(jī)用到的native方法相關(guān),java程序員不太關(guān)心。
(3)PC寄存器:也叫程序計(jì)數(shù)器。JVM支持多線程運(yùn)行,每個(gè)線程都有自己的程序計(jì)數(shù)器。若當(dāng)前執(zhí)行的是JVM的方法,則該寄存器中保存當(dāng)前執(zhí)行指令的地址,若執(zhí)行native方法,則為空。
(4)堆:堆內(nèi)存是JVM所有線程共享的部分,虛擬機(jī)啟動(dòng)時(shí)就已經(jīng)創(chuàng)建。所有對象和數(shù)組都在堆上進(jìn)行分配。這部分空間可通過GC進(jìn)行回收,當(dāng)申請不到空間時(shí)會(huì)拋出OutOfMemoryError。
(5)方法區(qū):所有線程共享。主要用于存儲(chǔ)類的信息,常量池,方法數(shù)據(jù),方法代碼等。
4. 執(zhí)行引擎
方法調(diào)用會(huì)導(dǎo)致棧幀的入棧,會(huì)確定調(diào)用哪一個(gè)方法。
(1)棧幀。程序的執(zhí)行對應(yīng)著棧幀的入棧和出棧,棧幀主要包括:局部變量表、操作數(shù)棧、動(dòng)態(tài)連接、方法返回地址等。
(2)方法調(diào)用。
解析調(diào)用:類加載的解析階段,會(huì)將其中一部分符號引用轉(zhuǎn)化為直接引用,這種解析的前提是方法在程序真正運(yùn)行之前就有一個(gè)可確定的調(diào)用版本。編譯期可確定調(diào)用方法的版本:靜態(tài)方法、私有方法、實(shí)例構(gòu)造器、父類方法。
分派調(diào)用:
a. 靜態(tài)分派:發(fā)生在編譯階段。所有依賴于靜態(tài)類型來定位方法執(zhí)行版本的分派動(dòng)作成為靜態(tài)分派,典型方法是重載。javac編譯器根據(jù)參數(shù)的靜態(tài)類型決定使用哪個(gè)重載版本。
b. 動(dòng)態(tài)分派:運(yùn)行期根據(jù)實(shí)際類型確定方法執(zhí)行版本。與方法重寫有密切關(guān)系。
c. 單分派和多分派:單分派是根據(jù)一個(gè)宗量對目標(biāo)方法進(jìn)行選擇,多分派是根據(jù)多于一個(gè)宗量對目標(biāo)方法進(jìn)行選擇。
(3)執(zhí)行引擎需將字節(jié)碼轉(zhuǎn)換成可以直接被JVM執(zhí)行的語言,可通過以下兩種方式轉(zhuǎn)換:
a. 解釋器:一條一條的讀取,解釋并且執(zhí)行字節(jié)碼指令
b. 即時(shí)編譯器:執(zhí)行引擎首先按照解釋執(zhí)行的方式來執(zhí)行,在合適的時(shí)候,即時(shí)編譯器把整段字節(jié)碼編譯成本地代碼。內(nèi)置了JIT編譯器的JVM都會(huì)檢查方法的執(zhí)行頻率,如果一個(gè)方法的執(zhí)行頻率超過一個(gè)特定的值的話,那么這個(gè)方法就會(huì)被編譯成本地代碼。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Maven項(xiàng)目執(zhí)行生命周期相關(guān)操作時(shí)出現(xiàn)錯(cuò)誤:does not match a
當(dāng)pom文件中的gav標(biāo)簽格式錯(cuò)誤,如出現(xiàn)中文或空格,會(huì)導(dǎo)致與有效的id模式不匹配錯(cuò)誤,gav標(biāo)簽應(yīng)僅包含數(shù)字、字母和下劃線,解決方法是修改標(biāo)簽中的中文為英文,刪除多余空格,并刷新pom文件,例如,將中文"測試"改為英文"test"2024-09-09SpringSecurity實(shí)現(xiàn)圖形驗(yàn)證碼功能的實(shí)例代碼
Spring Security 的前身是 Acegi Security ,是 Spring 項(xiàng)目組中用來提供安全認(rèn)證服務(wù)的框架。這篇文章主要介紹了SpringSecurity實(shí)現(xiàn)圖形驗(yàn)證碼功能,需要的朋友可以參考下2018-10-10Springboot項(xiàng)目打war包docker包找不到resource下靜態(tài)資源的解決方案
今天小編就為大家分享一篇關(guān)于Springboot項(xiàng)目打war包docker包找不到resource下靜態(tài)資源的解決方案,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-03-03springboot+chatgpt+chatUI Pro開發(fā)智能聊天工具的實(shí)踐
本文主要介紹了springboot+chatgpt+chatUI Pro開發(fā)智能聊天工具的實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04SpringCloud負(fù)載均衡實(shí)現(xiàn)定向路由詳情
這篇文章主要介紹了SpringCloud負(fù)載均衡實(shí)現(xiàn)定向路由詳情,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08