執行引擎是Java虛擬機的核心組成部分之一。java
首先,想一想C++和Java在編譯和運行時到底有啥不同?jvm
下圖左邊,C++發佈的就是機器指令,優化
而下圖右邊Java發佈的是字節碼,字節碼在運行時經過JVM的類加載器,加載到JVM的虛擬內存的方法區,線程
再經過編譯器、解釋器作一次轉換生成機器指令。執行引擎正是執行了這樣的過程:輸入的是內存中的字節碼,處理過程是字節碼解析的 等效過程,輸出的是執行結果。對象
其次,再來看下圖,JVM的內存結構:blog
1、執行方法。接口
每一個線程在建立後,都會產生一個程序計數器(pc)和棧(Stack)。內存
其中pc中存放了下一條將要執行的指令;ci
Stack中存放Stack Frame,存儲了 當前正在執行的方法的信息,get
每一個方法的執行都會產生Stack Frame,Stack Frame中存放了 傳遞給方法的參數、方法內的局部變量以及操做數棧;
操做數棧用於存放指令運算的中間結果;
操做數棧在概念上很像CPU寄存器(CPU的內部元件:指令寄存器IR和程序計數器PC)。
java虛擬機沒法使用寄存器,因此就用 操做數棧 來存放數據。
虛擬機把操做數棧做爲它的工做區 —— 大多數指令都要從這裏彈出數據,執行運算,而後把結果壓回操做數棧。
好比,iadd指令就要從操做數棧中彈出兩個整數,執行加法運算,其結果又壓回到操做數棧中。
基於(操做數)棧的指令集 和基於寄存器的區別,
基於棧的指令集 是和硬件無關的,而基於寄存器則依賴於硬件基礎。
基於寄存器在效率上優點。
可是虛擬機的出現,就是爲了提供跨平臺的支持,因此jvm的執行引擎是基於棧的指令集。
當方法執行完畢後則從Stack中彈出,繼續其餘方法的執行。
在繼續執行方法時,JVM主要提供了invokestatic、invokevirtual、invokeinterface和invokespecial四種指令來執行。
在類加載的第二階段--連接的第三階段--解析,就肯定下來的,屬於編譯期可知,運行期不可變的方法:
(1) invokestatic:調用類的static方法,屬於綁定類的調用
(2) invokespecial: 調用構造器,私有方法和父類方法,外部不可訪問,綁定實例對象
還有一種是在運行時候解析的,只有在運行時才能肯定下來的,主要包含如下兩方面:
(3) invokeinterface:調用接口方法,不肯定調用那一個實現類
(4) invokevirtual: 調用虛方法,不肯定調用哪個實現類
2、執行技術
主要的執行技術有:解釋,即時編譯,自適應優化、芯片級直接執行
(1)解釋:屬於第一代JVM;
(2)即時編譯:JIT屬於第二代JVM;
(3)自適應優化:(目前Sun的HotspotJVM採用這種技術)吸收第一代JVM和第二代JVM的經驗,採用二者結合的方式。
開始對全部的代碼都採起解釋執行的方式,
並監視代碼執行狀況,而後對那些 常常 調用的方法啓動一個後臺線程,將其編譯爲本地代碼,並進行仔細優化。
若方法再也不頻繁使用,則取消編譯過的代碼,仍對其進行解釋執行;
(4)芯片級直接執行:內嵌在芯片上,用本地方法執行Java字節碼。