作為開發(fā)人員,了解 JVM 的架構(gòu)非常重要,因?yàn)樗刮覀兡軌蚋行У鼐帉懘a。
什么是 JVM?
虛擬機(jī)是物理機(jī)的軟件實(shí)現(xiàn)。JAVA 是根據(jù) WORA(一次編寫,隨處運(yùn)行)的概念開發(fā)的,它在 VM 上運(yùn)行。編譯器將 Java 文件編譯為 Java .class 文件,然后將該 .class 文件輸入到 JVM 中,JVM 加載并執(zhí)行該類文件。下面是JVM的架構(gòu)圖。
JVM 是如何工作的?
如上架構(gòu)圖所示,JVM主要分為三個(gè)子系統(tǒng):類加載器子系統(tǒng)、運(yùn)行時(shí)數(shù)據(jù)區(qū)、執(zhí)行引擎。
1. 類加載器子系統(tǒng)
Java 的動態(tài)類加載功能由類加載器子系統(tǒng)處理。它加載,鏈接,并在運(yùn)行時(shí)而不是編譯時(shí)第一次引用類時(shí)初始化類文件。
1)加載
類將由該組件加載。BootStrap ClassLoader、Extension ClassLoader 和 Application ClassLoader 是三個(gè)有助于實(shí)現(xiàn)它的類加載器。
l BootStrap ClassLoader – 負(fù)責(zé)從引導(dǎo)類路徑加載類,除了 rt.jar。此加載程序?qū)@得最高優(yōu)先級。
l Extension ClassLoader – 負(fù)責(zé)加載 ext 文件夾 (jrelib) 中的類。
l Application ClassLoader——負(fù)責(zé)加載Application Level Classpath、路徑提到的環(huán)境變量等。
上述類加載器在加載類文件時(shí)將遵循委托層次算法。
2)鏈接
l 驗(yàn)證 - 字節(jié)碼驗(yàn)證器將驗(yàn)證生成的字節(jié)碼是否正確,如果驗(yàn)證失敗,我們將收到驗(yàn)證錯(cuò)誤。
l 準(zhǔn)備 - 對于所有靜態(tài)變量,內(nèi)存將被分配并分配默認(rèn)值。
3)初始化
這是類加載的最后階段,在這里,所有靜態(tài)變量都將被賦予原始值,并且將執(zhí)行靜態(tài)塊。
2. 運(yùn)行時(shí)數(shù)據(jù)區(qū)
運(yùn)行時(shí)數(shù)據(jù)區(qū)分為五個(gè)主要部分:
1)方法區(qū)——所有類級別的數(shù)據(jù)都將存儲在這里,包括靜態(tài)變量。每個(gè)JVM只有一個(gè)方法區(qū),它是一個(gè)共享資源。Java培訓(xùn)班的課程都是系統(tǒng)全面的整體,無論個(gè)人基礎(chǔ)的好壞,都能真正做到從0開始,循序漸進(jìn)的過渡到實(shí)際項(xiàng)目演練,在實(shí)際項(xiàng)目中驗(yàn)證所學(xué)知識的掌握程度,這是個(gè)人自學(xué)難以企及的巨大優(yōu)勢。
2)堆區(qū)——所有對象及其對應(yīng)的實(shí)例變量和數(shù)組都將存儲在這里,每個(gè) JVM 也有一個(gè)堆區(qū)。Method 和 Heap 區(qū)域?yàn)槎鄠€(gè)線程共享內(nèi)存。
3)堆棧區(qū)——對于每個(gè)線程,將創(chuàng)建一個(gè)單獨(dú)的運(yùn)行時(shí)堆棧。對于每個(gè)方法調(diào)用,都會在堆棧內(nèi)存中創(chuàng)建一個(gè)條目,稱為堆棧幀。所有局部變量都將在堆棧內(nèi)存中創(chuàng)建。堆棧區(qū)域是線程安全的,因?yàn)樗皇枪蚕碣Y源。Stack Frame 分為三個(gè)子實(shí)體:
l 局部變量數(shù)組 - 與方法相關(guān),涉及多少局部變量以及相應(yīng)的值將存儲在這里。
l 操作數(shù)棧——如果需要執(zhí)行任何中間操作,操作數(shù)棧充當(dāng)運(yùn)行時(shí)工作區(qū)來執(zhí)行操作。
l 幀數(shù)據(jù)——與方法對應(yīng)的所有符號都存儲在這里。在任何異常的情況下,catch 塊信息將保存在幀數(shù)據(jù)中。
4)PC 寄存器——每個(gè)線程都有單獨(dú)的 PC 寄存器,用于保存當(dāng)前執(zhí)行指令的地址,一旦指令執(zhí)行,PC 寄存器將被下一條指令更新。
5)本機(jī)方法堆棧——本機(jī)方法堆棧保存本機(jī)方法信息。對于每個(gè)線程,將創(chuàng)建一個(gè)單獨(dú)的本機(jī)方法堆棧。
3.執(zhí)行引擎
分配給運(yùn)行時(shí)數(shù)據(jù)區(qū)的字節(jié)碼將由執(zhí)行引擎執(zhí)行,執(zhí)行引擎讀取字節(jié)碼并逐段執(zhí)行。
1)解釋器——解釋器更快地解釋字節(jié)碼,但執(zhí)行速度很慢。解釋器的缺點(diǎn)是當(dāng)一個(gè)方法被多次調(diào)用時(shí),每次都需要新的解釋。
2)JIT 編譯器——JIT 編譯器消除了解釋器的缺點(diǎn)。執(zhí)行引擎將在解釋器的幫助下轉(zhuǎn)換字節(jié)碼,但當(dāng)它發(fā)現(xiàn)重復(fù)的代碼時(shí),它會使用 JIT 編譯器,編譯整個(gè)字節(jié)碼并將其更改為本地代碼。該原生代碼將直接用于重復(fù)的方法調(diào)用,從而提高系統(tǒng)的性能。
l 中間代碼生成器——生成中間代碼
l 代碼優(yōu)化器——負(fù)責(zé)優(yōu)化上面生成的中間代碼
l 目標(biāo)代碼生成器——負(fù)責(zé)生成機(jī)器代碼或本機(jī)代碼
l 探查器——一個(gè)特殊的組件,負(fù)責(zé)查找熱點(diǎn),即是否多次調(diào)用該方法。
3)垃圾收集器——收集和刪除未引用的對象。垃圾回收可以通過調(diào)用 System.gc() 來觸發(fā),但不能保證執(zhí)行。JVM 的垃圾收集收集創(chuàng)建的對象。
Java 本地接口(JNI)將與本機(jī)方法庫交互,并提供執(zhí)行引擎所需的本機(jī)庫。本機(jī)方法庫是執(zhí)行引擎所需的本機(jī)庫的集合。