1、 什么是JVM
JVM的全稱是Java Virtual Machine(Java虛擬機),它通過模擬一個計算機來達到計算機所具有的計算功能。
2、 JVM體系結(jié)構(gòu)詳解
JVM的結(jié)構(gòu)基本上由四部分組成:
----類加載器(ClassLoader):在JVM啟動時或運行時將需要的class加載到JVM中。
----執(zhí)行引擎:負責(zé)執(zhí)行class文件中包含的字節(jié)碼命令,相當(dāng)于實際機器上的CPU。
執(zhí)行引擎也就是執(zhí)行一條條代碼的流程,而代碼都包含在方法內(nèi),所以執(zhí)行引擎本質(zhì)上就是執(zhí)行一個個方法所串起來的流程,也就是對應(yīng)我們通常所說的Java線程,每個Java線程就是一個執(zhí)行引擎的實例。
----內(nèi)存區(qū):將內(nèi)存區(qū)劃分成若干個區(qū)以模擬實際機器上的存儲、記錄和調(diào)度功能模塊,
如實際機器上的各種功能的寄存器或者PC指針的記錄器等。
執(zhí)行引擎在執(zhí)行一段程序時需要存儲一些東西,如操作碼需要的操作結(jié)果、操作數(shù)等,這些都保存在內(nèi)存中。
----本地方法調(diào)用:調(diào)用C或C++實現(xiàn)的本地方法的代碼返回結(jié)果等。
3、 JVM工作機制
通常一個程序從編寫到執(zhí)行會經(jīng)歷一下一些階段:
源代碼(source code)→預(yù)處理器(preprocessor)→編譯器(compiler)→匯編程序(assembler)→目標代碼(object code)→鏈接器(Linker)→可執(zhí)行程序(executables)
除了源代碼和最后的可執(zhí)行程序,中間的所有環(huán)節(jié)都是由現(xiàn)代意義上的編譯器統(tǒng)一完成的。
不管是何種指令集都只有幾種基本的元素:加、減、乘、求余、求模等。這些運算又可以 進一步分解成二進制運算:與、或、異或等。這些運算又通過指令來完成,而指令的核心目的就是確定需要運算的種類(操作碼)和需要運算的數(shù)據(jù)(操作數(shù)),以及從哪里(寄存器或棧)獲取操作數(shù),將運算結(jié)果存放到什么地方(寄存器或是棧)等。這種不同的操作方式又將指令劃分成:一地址指令、二地址指令、三地址指令和零地址指令等n地址指令。相應(yīng)的指令集會有對應(yīng)的架構(gòu)實現(xiàn),如基于寄存器的架構(gòu)實現(xiàn)或基于棧的架構(gòu)實現(xiàn),這里的基于寄存器或者棧都是指在一個指令中的操作數(shù)是如何存取的。
4、 JVM基于棧設(shè)計的理由
----JVM要設(shè)計成與平臺無關(guān)的,而平臺無關(guān)性就要保證在沒有或有很少的寄存器的機器上也要同樣能正確的運行代碼。
----為了指令的緊湊性。
5、 執(zhí)行引擎的架構(gòu)設(shè)計
每當(dāng)創(chuàng)建一個新的線程時,JVM會為這個線程創(chuàng)建一個Java棧,并分配一個PC寄存器,PC寄存器會指向這個線程的第一行可執(zhí)行代碼。每當(dāng)執(zhí)行一個新的方法時,JVM會為這個棧分配一個新的棧幀,棧幀包含了對應(yīng)方法的參數(shù)、內(nèi)部變量、執(zhí)行結(jié)果等。
6、 執(zhí)行引擎的執(zhí)行過程
直接看上圖這段代碼,我們來對main方法中的字節(jié)碼指令做一個分析:
代碼執(zhí)行之前,寄存器的指針指向第一條指令的地址(偏移量0),局部變量區(qū)和操作棧都沒有數(shù)據(jù)。代碼開始執(zhí)行之后,根據(jù)指令開始操作棧和變量區(qū)進行運算。
注意:當(dāng)main方法中引用了其他方法時,則會創(chuàng)建新的棧幀,寄存器仍舊只有一個。當(dāng)執(zhí)行到引用方法時,執(zhí)行引擎會創(chuàng)建一個新的棧幀,而寄存器保存的是當(dāng)前棧幀的第一條指令地址,所以值是0。
當(dāng)執(zhí)行完return指令時,整個方法對應(yīng)的棧幀也將撤銷,如果當(dāng)前線程對應(yīng)的Java棧中沒有棧幀,這個Java棧也將被JVM撤銷,整個JVM退出。