深入分析JVM執行引擎

来源:https://www.cnblogs.com/cicada-smile/archive/2022/08/29/16633767.html
-Advertisement-
Play Games

JVM執行引擎的作用就是將位元組碼指令解釋或者編譯為對應平臺上的本地機器指令。簡單來說,執行引擎充當了將高級語言翻譯為機器語言的翻譯者。 ...


程式和機器溝通的橋梁

一、閑聊

相信很多朋友在出國旅游,或者與外國友人溝通的過程中,都會遇到語言不通的煩惱。這時候我們就需要掌握對應的外語或者擁有一部翻譯機。而筆者只會中文,所以需要藉助一部翻譯器才能與不懂中文的外國友人交流。咱們的執行引擎就類似於這部“翻譯機”。

二、概述

執行引擎的作用就是將位元組碼指令解釋或者編譯為對應平臺上的本地機器指令。簡單來說,執行引擎充當了將高級語言翻譯為機器語言的翻譯者。對於Hotspot虛擬機,執行引擎中包含兩部分:解釋器和JIT編譯器(即時編譯器)。下圖是執行引擎的原理:

三、解釋器

解釋器所承擔的角色就是一個運行時翻譯者,將位元組碼文件中的內容翻譯為對應平臺的本地機器碼指令。當一條位元組碼指令被解釋執行後,接著再根據pc寄存器中記錄的下一條需要被執行的位元組碼指令執行解釋操作。JVM解釋器一共有兩套,一套是遠古的位元組碼解釋器,另一套是現在普遍使用的模板解釋器

1、位元組碼解釋器

位元組碼解釋器在執行過程中通過純軟體代碼模擬位元組碼執行,效率非常低。

2、模板解釋器

模板解釋器將每一條位元組碼和一個模板函數關聯,模板函數中直接產生這條位元組碼指令執行時的機器碼,從而提高瞭解釋器的性能。在常用的HotSpot VM中,解釋器主要由Interpreter模板和code模塊構成。Interpreter模板:實現瞭解釋器的核心功能。code模塊:用於管理HotSpot VM在運行時生成的本地機器碼指令。

四、即時編譯器(JIT編譯器)

即時編譯器的目的是避免函數被解釋執行,而是將整個函數體編譯成機器碼指令,每次函數執行時,只執行編譯後的機器碼即可,這種方式可以大大的提高效率。

1、熱點代碼及探測方式

當然,是否需要JIT編譯器將位元組碼直接編譯成對應平臺的機器碼,需要根據代碼被調用的執行頻率而定。需要被JIT編譯器編譯成機器碼的位元組碼,也稱為熱點代碼,JIT編譯器會對熱點代碼做出深度優化,將其從位元組碼編譯成機器碼,並緩存到方法區,提高代碼的執行效率。
JIT編譯的方式發生在方法執行過程中,因此也被稱之為_棧上替換_,或簡稱OSR(On Stack Replacement)編譯。通過熱點探測的方法,判斷一個方法被調用多少次,或迴圈體執行多少次才可以達到閾值,進行編譯。而Hotspot VM熱點探測的方式是基於計數器實現的。這種基於技術的熱點探測方式又分為兩種:1.方法調用計數器 2.回邊計數器

關於棧上替換這裡筆者不展開贅述,有興趣的小伙伴可以自行瞭解下

1.1方法調用計數器

方法調用計數器用於統計方法調用次數,它的預設閾值是client模式下是1500次,在server模式下是10000次。超過這個閾值,就會觸發JIT編譯。當然,這個閾值也可以通過修改虛擬機參數-XX:CompileThreshold來手動指定。
當一個方法被調用的時候,會優先檢查該方法是否被JIT編譯過,如果存在,則優先使用編譯過的本地代碼來執行,如果不存在,則將此方法的調用計數器加一,然後再判斷計數器的值是否超過配置的閾值。如果已經超過了,就會向JIT編譯器提交一個該方法的編譯請求。下麵是方法調用計數器執行的流程圖:

關於方法調用計數器,如果不做任何設置,方法調用計數器統計的並不是方法被調用的絕對次數,而是一個相對執行的頻率。當超過一定的時間限度,如果方法的調用次數仍然達不到閾值,那這個方法的調用計數器就會被減少一半,這個過程稱為方法調用計數器的熱度衰減,而這段時間被稱作為該方法的半衰周期
進行熱度衰減的過程是虛擬機進行垃圾回收的時候順便進行的,舉手之勞而已。可以使用虛擬機參數-XX:-UseCounterDecay來關閉熱度衰減。這樣的話,只要運行時間足夠長,絕大部分方法都會被編譯成本地代碼。最後,還可以使用-XX:CounterHalfLifeTime參數設置半衰周期的時間,單位為秒。

1.2回邊計數器

它的作用是統計一個方法中迴圈體代碼執行次數,在位元組碼中遇到控制流向後,跳轉的指令稱為“回邊”。顯然,建立回邊計數器統計的目的是為了觸發OSR編譯。下麵是回邊計數器執行的流程圖:

關於OSR編譯上文中有提到

2、即時編譯器分類

在Hotspot VM中,內嵌有兩個JIT編譯器,分別為client compiler和server compiler,但是大多數情況下我們簡稱C1編譯器和C2編譯器。可以通過命令顯示的指定JVM在運行時到底使用哪種JIT編譯器。

2.1 c1編譯器

指定Java虛擬機運行在client模式下,使用C1編譯器。C1編譯器會對位元組碼進行簡單和可靠的優化,耗時短。以達到更快的編譯速度,但是編譯後的代碼執行速度相對慢。C1編譯器主要有方法內聯,去虛擬化,冗餘消除。

  1. 方法內聯:將引用的函數代碼編譯到引用點處,這樣可以減少棧幀的生成,減少參數傳遞以及跳轉過程。
  2. 去虛擬化:對唯一實現的類進行內聯。
  3. 冗餘消除:在運行期間把一些不會執行的代碼疊掉。

2.2 c2編譯器

指定Java虛擬機運行在server模式下,使用C2編譯器。C2編譯器對代碼優化時間長,編譯時間也長。但是編譯後的代碼執行速度比較快。C2的優化主要在全局層面,逃逸分析式優化的基礎。基於逃逸分析,C2上有如下幾種優化:

  1. 標量替換:用標量值代替聚合對象的屬性值。
  2. 棧上分配:對於未逃逸的對象分配在棧上而不是堆上。
  3. 同步消除:清楚同步操作,通常指synchronized。

2.3 Graal編譯器

JDK10起,在C1編譯器和C2編譯器之後,HotSpot VM新增了一個Graal即時編譯器。編譯效果短短幾年的時間就追平了C2編譯器。目前,帶著“實驗狀態”標簽,需要使用開關參數-XX:+UnlockExperimentalVMOptions-XX:+UseJVMCICompiler去激活這個編譯器,才能使用。

五、解釋器和JIT並存

為什麼需要解釋器和JIT並存,原因有幾點:

  1. 當程式啟動的時候,解釋器可以馬上發揮作用,省去編譯的時間。
  2. 編譯器想要執行,需要把位元組碼編譯成本地機器碼,並且緩存編譯後的機器碼,編譯需要一定的時間。
  3. 編譯後的本地機器碼,執行效率高。所以,在兩種並存的模式下,解釋器首先發揮作用,而不必等到即時編譯器全部編譯完在執行,這樣可以省去不必要的編譯時間。
  4. 隨著程式繼續不斷運行,編譯器發揮作用,根據熱點探測功能,把越來越多的位元組碼編譯成本地機器碼,獲得更高的執行效率。

六、執行引擎執行程式的方式

在預設的情況下,HotSpot VM採用的是解釋器和JIT編譯器並存的架構,當然讀者可以根據具體的應用場景,通過虛擬機參數,為虛擬機指定在運行時到底是完全採用解釋器執行,還是完全採用即時編譯器執行。

  1. -Xint:完全採用解釋器模式執行程式
  2. -XComp:完全採用即時編譯器模式執行程式。如果即時編譯器出現問題,解釋器會介入執行;
  3. -Xmixed:採用解釋器+即時編譯器的混合模式共同執行程式,HotStop VM預設就是這個模式。
Gitee主頁: https://gitee.com/cicadasmile/butte-java-note
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 強制更新和創建低開銷的靜態組件 點擊打開視頻講解更加詳細 強制更新 如果你發現你自己需要在 Vue 中做一次強制更新,99.9% 的情況,是你在某個地方做錯了事。 你可能還沒有留意到數組或對象的變更檢測註意事項,或者你可能依賴了一個未被 Vue 的響應式系統追蹤的狀態。 然而,如果你已經做到了上述的 ...
  • 前端埋點對於那些營銷活動的項目是必須的,它可以反應出用戶的喜好與習慣,從而讓項目的運營者們能夠調整策略優化流程提高用戶體驗從而獲取更多的$。這篇文章將實現一個Vue3版本的埋點上報插件,主要功能有 通過Vue自定義指令形式實現點擊事件上報 提供手動調用上報方法 上報每個頁面訪問人數與次數(UV,PV ...
  • 小記: 本章 主要瞭解命令式、聲明式、性能與可維護性的權衡、虛擬Dom的性能、運行時和編譯時。Vue就是通過權衡這幾種方式的優缺點進行框架設計 命令式、聲明式 對比 框架對比 命令式 聲明式 特點 只關註過程 只關註結果 優點 性能最高 心智負擔小,維護性高 優缺點 心智負擔大、維護性差 性能較高 ...
  • YSLaunchar-a1.0 模型 基本介紹 本文不考慮所有具體的實現方法,之後會有更完整第二版發出 該程式計劃使用 julia 語言編寫,目前版本(1.7)並不包含類(class),取而代之,我會使用 julia 提供的兩種結構體完成。 考慮了很久,我將會把所有版本,玩家列表使用字典的形式。 主 ...
  • 以下內容為本人的著作,如需要轉載,請聲明原文鏈接 微信公眾號「englyf」https://www.cnblogs.com/englyf/p/16637890.html 如果不是機緣巧合,當年轉到C++之後,恐怕很難再有機會還寫C的代碼。面向對象在現代coding中,就像聖經一樣,在碼農的口中自帶光 ...
  • 看《C++ Primer Plus》時整理的學習筆記,部分內容完全摘抄自《C++ Primer Plus》(第6版)中文版,Stephen Prata 著,張海龍 袁國忠譯,人民郵電出版社。只做學習記錄用途。 ...
  • 泛型 筆記目錄:(https://www.cnblogs.com/wenjie2000/p/16378441.html) 泛型的理解和好處 看一個需求 請編寫程式,在ArrayList中,添加3個Dog對象 Dog對象含有name和age,並輸出name和age(要求使用getXxx()) 先使用傳 ...
  • 目錄 一.OpenGL 伽馬線 1.IOS Object-C 版本 2.Windows OpenGL ES 版本 3.Windows OpenGL 版本 二.OpenGL 伽馬線 GLSL Shader 三.猜你喜歡 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目錄 >> ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...