十一、執行引擎
1、執行引擎概述
執行引擎是Java虛拟機核心的組成部分之一,虛拟機的執行引擎由軟體自行實作,能夠執行不被硬體直接支援的指令格式,實體機的執行引擎是作業系統層面上。
執行引擎的工作過程:
- 執行引擎在執行的過程中究竟需要執行什麼樣的位元組碼指令完全依賴于PC寄存器。
- 每當執行完一項指令操作後,PC寄存器就會更新下一條需要被執行的指令位址。
- 當然方法在執行的過程中,執行引擎有可能會通過存儲在局部變量表中的對象引用準确定位到存儲在Java堆區中的對象執行個體資訊,以及通過對象頭中的中繼資料指針定位到目标對象的類型資訊。
2、Java 代碼編譯和執行過程
大部分的程式代碼轉換成實體機的目标代碼或虛拟機能執行的指令集之前,都需要經過上圖中的各個步驟
為什麼說 Java是半編譯半解釋型語言?
- JVM在執行Java代碼的時候,通常會将解釋執行與編譯執行二者結合起來進行
3、機器碼,指令,彙編語言
機器碼:各種采用二進制編碼方式表示的指令,叫做機器指令碼、機器語言。機器指令與CPU緊密相關,不同種類的CPU所對應的機器指令也就不同。
指令:
- 由于機器碼由01組成,可讀性太差。于是人們發明了指令
- 指令就是把機器碼特定的0和1序列,簡化成對應的指令,一般為英文編寫如mov,inc等,可讀性稍好
- 由于不同的硬體平台,執行同一個操作,對應的機器碼可能不同。是以不同的硬體平台的同一種指令,對應的機器碼也可能不同
指令集:
- 不同硬體平台,各自支援的指令,是有差别的。是以每個平台所支援的指令,稱之為對應平台的指令集
- x86指令集,對應的x86架構的平台
- ARM指令集,對應的是ARM架構的平台
彙編:
- 由于指令的可讀性太差,于是又有了彙編語言
- 彙編語言用助記符代替機器指令的操作碼,用位址符号或标号,代替指令或操作數的位址。
- 彙編語言要翻譯成機器指令碼,計算機才能識别和執行
4、解釋器
當Java虛拟機啟動時,會根據預定義的規範對位元組碼采用逐行解釋的方式執行,将每條位元組碼檔案中的内容翻譯為對應平台的本地機器指令執行。解析器真正意義上所承擔的角色就是一個運作時翻譯者,将位元組碼檔案中的内容翻譯為對應的平台的本地機器指令執行。
當一條位元組碼指令被解釋執行完成後,接着在根據PC寄存器中的記錄下一條需要被執行的位元組碼執行解釋執行。
- 古老的位元組碼解釋器
- 現在普遍使用的模闆解釋器:将每一條位元組碼和一個模闆函數相關聯,模闆函數直接産生這條位元組碼執行時的機器碼,提高解釋器的性能。
HotSpot中:
- Interpreter子產品:實作了解釋器的核心功能。
- Code子產品:用于管理HotSpot在運作時生成的本地機器指令。
5、JIT 編譯器
虛拟機将源代碼直接編譯成和本地機器平台相關的機器語言。
JVM平台支援一種叫做即時編譯的技術,目的是避免解釋執行,而是将整個函數體編譯成機器碼,每次函數執行時,隻執行編譯後的機器碼即可。使執行效率大幅提升。
為什麼兩條腿走路?
- 首先程式啟動後,解釋器可以馬上發揮作用,省去編譯時間,立即執行。
- 編譯器要想發揮作用,把代碼編譯成本地代碼,需要一定的執行時間。但編譯為本地代碼後執行效率更高。
- 對于服務端應用,啟動時間并非關注重點,但是對于看重新開機動時間的應用場景,就需要找到一個平衡點。
- 當 Java虛拟機啟動時,解釋器可以首先發揮作用,而不是等待即時編譯器全部編譯完成後再執行,這樣可以省去很多不必要的編譯時間,随着時間的推移,編譯器發揮作用,把越來越多的代碼編譯成本地代碼,獲得更高的執行效率。
6、熱點代碼及探測方式
什麼時候選擇 JIT?
需要根據代碼被調用執行的頻率而定,需要被編譯為本地代碼的位元組碼,也稱之為熱點代碼。JIT編譯器會在運作時針對頻繁調用的熱點代碼做出深度優化,将其直接編譯為對應平台的本地機器指令。以此提升 Java程式的執行性能。
一個被多次調用的方法,或者一個方法體内部循環次數較多的循環體,都可以被稱之為熱點代碼。是以可以通過 JIT編譯器編譯為本地機器指令,由于這種編譯方法發生在方法的執行過程中,是以也被稱之為棧上替換,OSR On Statck Replacement。
一個方法調用都少次才能達到标準?hotspot采用的是基于計數器的熱點探測:
- 方法調用計數器
- 統計方法調用次數,預設門檻值,Client模式下是1500次,Server模式下是10000次
- -XX:CompileThreshold
- 回邊計數器
- 統計循環體執行的循環次數
JVM 學習筆記十一、執行引擎十一、執行引擎
- 統計循環體執行的循環次數
- 當一個方法被調用時,如果不存在已被編譯過的版本,則将此方法的調用計數器+1,然後判斷方法調用計數器與回邊計數器之和,是否超過方法調用計數器的門檻值。如果已經超過,會向即時編譯器送出一個該方法的代碼編譯請求。
- 熱度衰減
- 當超過一定的時間限度,如果方法調用次數仍然不足以送出即時編譯器編譯,那麼這個方法的調用計數器就會被減少一半。
- -XX:UseCounterHalfLifeTime參數設定半衰周期的時間,機關是秒
7、執行模式
hotspot可以設定程式執行的方式:
- Xint:完全采用解釋器模式執行
- -Xcomp:完全采用即時編譯器模式執行,如果即時編譯器出現問題,解釋器會介入執行
- -Xmixed:采用解釋器+即時編譯器的混合模式共同執行
JVM 學習筆記十一、執行引擎十一、執行引擎
hotspot中 JIT分類,内嵌兩個JIT編譯器,大多情況下簡稱C1,C2:
- -client:指定 Java虛拟機在Client模式下,并使用C1編譯器
- C1編譯器會對位元組碼進行簡單和可靠的優化,耗時短,以達到更快的編譯速度
- 方法内聯:将引用的函數代碼編譯到引用點處,減少棧幀的生成,減少參數傳遞以及跳轉過程
- 去虛拟化:對唯一的實作類進行内聯
- 備援消除:在運作期把一些不會執行的代碼折疊掉
- -server:指定虛拟機在server模式下,并使用C2編譯器
- C2進行耗時較長的優化,以及激進優化,但優化後的代碼執行效率更高
- 逃逸分析是優化的基礎,基于逃逸分析在C2上有幾種優化
- 标量替換:用标量值代替聚合對象的屬性值
- 棧上配置設定:對于未逃逸的對象配置設定在棧而不是堆
- 同步消除:清除同步操作,通常指synchronized