18-執(zhí)行引擎

一、執(zhí)行引擎概述

  • 執(zhí)行引擎是 Java 虛擬機(jī)核心的組成部分之一

  • “虛擬機(jī)”是一個(gè)相對(duì)于 “物理機(jī)” 的概念,這兩種機(jī)器都有代碼執(zhí)行能力夕凝,其區(qū)別是\color{#DC143C}{物理機(jī)的執(zhí)行引擎是直接建立在處理器、緩存户秤、指令集和操作系統(tǒng)層面上的}码秉,而\color{#DC143C}{虛擬機(jī)的執(zhí)行引擎則是由軟件自行實(shí)現(xiàn)的},因此可以不受物理?xiàng)l件制約地定制指令集與執(zhí)行引擎的結(jié)構(gòu)體系鸡号,能夠執(zhí)行那些不被硬件直接支持的指令集格式转砖。

  • JVM的主要任務(wù)是負(fù)責(zé) \color{#DC143C}{裝載字節(jié)碼到其內(nèi)部},但字節(jié)碼并不能夠直接運(yùn)行在操作系統(tǒng)上鲸伴,因?yàn)樽止?jié)碼指令并非等價(jià)于本地機(jī)器指令府蔗,它內(nèi)部包含的僅僅只是一些能夠被 JVM 所識(shí)別的字節(jié)碼指令、符號(hào)表汞窗,以及其他輔助信息

  • 那么姓赤,如果想要讓一個(gè) Java 程序運(yùn)行起來(lái),執(zhí)行引擎(Execution Engine)的任務(wù)就是將\color{#DC143C}{字節(jié)碼指令解釋/編譯為對(duì)應(yīng)平臺(tái)上的本地機(jī)器碼指令才可以}仲吏。簡(jiǎn)單來(lái)說(shuō)不铆,JVM中的執(zhí)行引擎充當(dāng)了將高級(jí)語(yǔ)言翻譯為機(jī)器語(yǔ)言的譯者

  • 執(zhí)行引擎的工作過(guò)程

    • 每當(dāng)執(zhí)行完一項(xiàng)指令操作后蝌焚,PC寄存器就會(huì)更新下一條需要被執(zhí)行的指令地址
    • 方法在執(zhí)行的過(guò)程中,執(zhí)行引擎有可能會(huì)通過(guò)存儲(chǔ)在\color{#DC143C}{局部變量表中對(duì)象引用準(zhǔn)備定位到存儲(chǔ)在Java堆區(qū)中的對(duì)象實(shí)例信息}誓斥,以及通過(guò)\color{#DC143C}{對(duì)象頭中的元數(shù)據(jù)指針定位到目標(biāo)對(duì)象的類型信息}
      image.png

二只洒、Java代碼編譯和執(zhí)行的過(guò)程

Java代碼編譯和執(zhí)行的過(guò)程.png
  • Java代碼編譯是由 Java源碼編譯器 來(lái)完成


    image.png
  • Java字節(jié)碼的執(zhí)行是由 JVM 執(zhí)行引擎 來(lái)完成


    image.png
  • 解釋器(Interpreter):當(dāng)Java虛擬機(jī)啟動(dòng)時(shí)會(huì)根據(jù)預(yù)定義的規(guī)范\color{#DC143C}{對(duì)字節(jié)碼采用逐行解釋的方式執(zhí)行},將每條字節(jié)碼文件中的內(nèi)容“翻譯”為對(duì)應(yīng)平臺(tái)的本地機(jī)器指令執(zhí)行

  • JIT(Just In Time Compiler)編譯器:虛擬機(jī)將源代碼直接編譯成和本地機(jī)器平臺(tái)相關(guān)的機(jī)器語(yǔ)言

三劳坑、機(jī)器碼毕谴、指令、匯編語(yǔ)言

  • 機(jī)器碼:各種用二進(jìn)制編碼方式表示的指令距芬。機(jī)器指令與CPU緊密相關(guān)涝开,不同的CPU所對(duì)應(yīng)的機(jī)器指令也不相同

  • 指令:指令就是把機(jī)器碼中特定的 0 和 1 序列,簡(jiǎn)化成對(duì)應(yīng)的指令框仔,可讀性會(huì)稍好忠寻。由于不同的硬件平臺(tái),執(zhí)行同一個(gè)操作存和,對(duì)應(yīng)的機(jī)器碼可能不同奕剃,所以不同的硬件平臺(tái)的同一種指令(如:mov),對(duì)應(yīng)的機(jī)器碼也可能不同

  • 指令集:不同的硬件平臺(tái)捐腿,各自支持的指令是不同的纵朋。因此每個(gè)平臺(tái)所支持的指令,稱之為對(duì)應(yīng)平臺(tái)的指令集

  • 匯編語(yǔ)言:由于指令的可讀性太差茄袖,于是發(fā)明了匯編語(yǔ)言操软。在不同的硬件平臺(tái),匯編語(yǔ)言對(duì)應(yīng)著不同的機(jī)器語(yǔ)言指令集宪祥,通過(guò)匯編過(guò)程轉(zhuǎn)換成機(jī)器指令

  • 高級(jí)語(yǔ)言:為了使計(jì)算機(jī)用戶編程更容易些聂薪,后來(lái)就出現(xiàn)了各種高級(jí)計(jì)算機(jī)語(yǔ)言。高級(jí)語(yǔ)言更接近人的語(yǔ)言蝗羊。

  • 當(dāng)計(jì)算機(jī)執(zhí)行高級(jí)語(yǔ)言編寫的程序時(shí)藏澳,仍然需要把程序解釋和編譯成機(jī)器的指令碼。完成這個(gè)過(guò)程的程序就叫做解釋程序和編譯程序耀找。

  • 字節(jié)碼

    • 字節(jié)碼是一種中間狀態(tài)(中間碼)的二進(jìn)制代碼(文件)翔悠,它比機(jī)器碼更抽象,需要直譯器轉(zhuǎn)譯后才能成為機(jī)器碼
    • 字節(jié)碼主要為了實(shí)現(xiàn)特定軟件運(yùn)行和軟件環(huán)境野芒、與硬件環(huán)境無(wú)關(guān)
    • 字節(jié)碼的實(shí)現(xiàn)方式是通過(guò)編譯器和虛擬機(jī)器蓄愁。編譯器將源碼編譯成字節(jié)碼,特定平臺(tái)上的虛擬機(jī)器將字節(jié)碼轉(zhuǎn)譯為可以直接執(zhí)行的指令

四狞悲、解釋器

  • JVM設(shè)計(jì)者們的初衷僅僅只是單純地\color{#DC143C}{為了滿足 Java 程序?qū)崿F(xiàn)跨平臺(tái)特性}撮抓,因此避免采用靜態(tài)編譯的方式直接生成本地機(jī)器指令,從而誕生了實(shí)現(xiàn)解釋器在運(yùn)行時(shí)采用逐行解釋字節(jié)碼執(zhí)行程序的想法

  • 解釋器真正意義上所承擔(dān)的角色就是一個(gè)運(yùn)行時(shí)“翻譯者”摇锋,將字節(jié)碼文件中的內(nèi)容“翻譯”為對(duì)應(yīng)平臺(tái)的本地機(jī)器指令執(zhí)行

  • 當(dāng)一條字節(jié)碼指令被解釋執(zhí)行完成后丹拯,接著再根據(jù) PC 寄存器中記錄的下一條需要被執(zhí)行的字節(jié)碼指令執(zhí)行解釋操作

  • 解釋器分類

    • 字節(jié)碼解釋器:在執(zhí)行時(shí)通過(guò)\color{#DC143C}{純軟件代碼}模擬字節(jié)碼的執(zhí)行站超,效率非常低下
    • 模板解釋器:將\color{#DC143C}{每一條字節(jié)碼和一個(gè)模板函數(shù)}相關(guān)聯(lián),模板函數(shù)中直接產(chǎn)生這條字節(jié)碼執(zhí)行時(shí)的機(jī)器碼咽笼,從而很大程度上提高了解釋器的性能
    • HotSpot VM 中顷编,解釋器主要由 Interpreter 模塊和 Code 模塊組成戚炫。
      • Interpreter模塊:實(shí)現(xiàn)了解釋器的核心功能
      • Code模塊:用于管理HotSpot VM 在運(yùn)行時(shí)生成的本地機(jī)器指令

五剑刑、JTI編譯器

Java代碼的執(zhí)行分類

  • 第一種是將源代碼編譯成字節(jié)碼文件,然后在運(yùn)行時(shí)通過(guò)\color{#DC143C}{ 解釋器 }將字節(jié)碼文件轉(zhuǎn)為機(jī)器碼執(zhí)行
  • 第二種是編譯執(zhí)行(直接編譯成機(jī)器碼)∷簦現(xiàn)代虛擬機(jī)為了提高執(zhí)行效率施掏,會(huì)使用即時(shí)編譯技術(shù)(JIT,Just In Time)將方法編譯成機(jī)器碼后再執(zhí)行茅糜。

HotSpot VM 的執(zhí)行方式

  • 當(dāng)虛擬機(jī)啟動(dòng)的時(shí)候七芭,\color{#DC143C}{ 解釋器可以首先發(fā)揮作用 },而不必等待\color{#DC143C}{ 即時(shí)編譯器全部編譯完成再執(zhí)行 }蔑赘,這樣可以省去許多不必要的編譯時(shí)間狸驳,并且隨著程序運(yùn)行時(shí)間的推移,即時(shí)編譯器逐漸發(fā)揮作用缩赛,根據(jù)\color{#DC143C}{熱點(diǎn)探測(cè)功能}耙箍,將有價(jià)值的字節(jié)碼編譯為本地機(jī)器指令,以換取更高的程序執(zhí)行效率酥馍。

熱點(diǎn)代碼及探測(cè)方式

  • 是否需要啟動(dòng) JIT編譯器將字節(jié)碼直接編譯為對(duì)應(yīng)平臺(tái)的本地機(jī)器指令辩昆,則需要根據(jù)代碼被調(diào)用\color{#DC143C}{ 執(zhí)行的頻率}而定。而那些需要被編譯為本地代碼的字節(jié)碼旨袒,也被稱為\color{#DC143C}{ 熱點(diǎn)代碼}汁针,JIT編譯器在運(yùn)行時(shí)會(huì)針對(duì)那些頻繁被調(diào)用的\color{#DC143C}{ 熱點(diǎn)代碼}做出\color{#DC143C}{ 深度優(yōu)化},將其直接編譯為對(duì)應(yīng)平臺(tái)的本地機(jī)器指令砚尽,以此提升 Java 程序的執(zhí)行性能

  • 一個(gè)被多次調(diào)用的方法施无,或者是一個(gè)方法體內(nèi)部循環(huán)次數(shù)較多的循環(huán)體都可以被稱為\color{#DC143C}{ 熱點(diǎn)代碼},一個(gè)方法被調(diào)用多少次才能成為\color{#DC143C}{ 熱點(diǎn)代碼}必孤,必然需要一個(gè)明確的閾值帆精,這里主要依靠\color{#DC143C}{ 熱點(diǎn)探測(cè)功能}

  • 目前HotSpot VM 所采用的熱點(diǎn)探測(cè)方式是基于計(jì)數(shù)器的熱點(diǎn)探測(cè)。HotSpot VM將會(huì)為每一個(gè)方法都建立 2 個(gè)不同類型的計(jì)數(shù)器隧魄,分別為方法調(diào)用計(jì)數(shù)器(Invocation Counter)和回邊計(jì)數(shù)器(Back Edge Counter)卓练。其中方法調(diào)用計(jì)數(shù)器用于統(tǒng)計(jì)方法的調(diào)用次數(shù),回邊計(jì)數(shù)器則用于統(tǒng)計(jì)循環(huán)體執(zhí)行的循環(huán)次數(shù)

方法調(diào)用計(jì)數(shù)器

  • 它的閾值在 Client 模式下是 1500 次购啄,在 Server 模式下是 10000 次襟企。超過(guò)這個(gè)閾值,就會(huì)觸發(fā) JIT 編譯
  • 這個(gè)閾值可以設(shè)置
-XX:CompileThreshold
  • 當(dāng)一個(gè)方法被調(diào)用時(shí)狮含,會(huì)先檢查該方法是否存在被 JIT 編譯過(guò)的版本顽悼,如果存在曼振,則優(yōu)先使用編譯后的本地代碼來(lái)執(zhí)行。如果不存在已被編譯過(guò)的版本蔚龙,則將此方法調(diào)用計(jì)數(shù)器值+1冰评,然后判斷方法調(diào)用計(jì)數(shù)器與回邊計(jì)數(shù)器值之和是否超過(guò)方法調(diào)用計(jì)數(shù)器的閾值。如果已經(jīng)超過(guò)閾值木羹,那么就會(huì)想即時(shí)編譯器提交一個(gè)該方法的代碼編譯請(qǐng)求


    image.png

熱度衰減

  • 如果不做任何設(shè)置甲雅,方法調(diào)用計(jì)數(shù)器統(tǒng)計(jì)的并不是方法被調(diào)用的絕對(duì)次數(shù),而是一個(gè)相對(duì)的執(zhí)行頻率坑填,即一段時(shí)間之內(nèi)方法被調(diào)用的次數(shù)抛人。當(dāng)超過(guò)一定的時(shí)間限度,如果方法的調(diào)用次數(shù)仍然不足以讓它提交給即時(shí)編譯器脐瑰,那這個(gè)方法的調(diào)用計(jì)數(shù)器就會(huì)被減少一半妖枚,這個(gè)過(guò)程稱為方法調(diào)用計(jì)數(shù)器熱度的衰減(Counter Decay),而這段時(shí)間就稱為此方法統(tǒng)計(jì)的半衰周期(Counter Half Life Time)

  • 進(jìn)行熱度衰減的動(dòng)作是在虛擬機(jī)進(jìn)行垃圾收集時(shí)順便進(jìn)行的苍在,可以使用虛擬機(jī)參數(shù)-XX:-UseCounterDecay 來(lái)關(guān)閉熱度衰減绝页,讓方法計(jì)數(shù)器統(tǒng)計(jì)方法調(diào)用的絕對(duì)次數(shù),這樣寂恬,只要系統(tǒng)運(yùn)行時(shí)間足夠長(zhǎng)续誉,絕大部分方法都會(huì)被編譯成本地代碼

  • 使用 -XX:CounterHalfLifeTime 參數(shù)設(shè)置半衰周期的時(shí)間,單位為秒

回邊計(jì)數(shù)器

  • 它的作用是統(tǒng)計(jì)一個(gè)方法中 循環(huán)體代碼執(zhí)行的次數(shù)掠剑,在字節(jié)碼中遇到控制流向后跳轉(zhuǎn)的指令稱為“回邊(Back Edge)”屈芜。顯然,建立回邊計(jì)數(shù)器統(tǒng)計(jì)的目的就是為了觸發(fā) OSR 編譯

HotSpot VM 設(shè)置程序執(zhí)行方式

缺省情況下HotSpot VM是采用解釋器與即時(shí)編譯器并存的架構(gòu)朴译,當(dāng)然開發(fā)人員可以根據(jù)具體的應(yīng)用場(chǎng)景井佑,通過(guò)指令顯示地為 Java 虛擬機(jī)指定在運(yùn)行時(shí)到底是完全采用 \color{#DC143C}{ 解釋器} 執(zhí)行,還是完全采用 \color{#DC143C}{ 即時(shí)編譯器 }執(zhí)行

  • 完全采用解釋器模式執(zhí)行程序
-Xint:
  • 完全采用即時(shí)編譯器模式執(zhí)行程序眠寿。如果即時(shí)編譯出現(xiàn)問(wèn)題躬翁,解釋器會(huì)介入執(zhí)行
-Xcomp:
  • 采用解釋器+即時(shí)編譯器的混合模式共同執(zhí)行程序
-Xmixed:

HotSpot VM中JIT分類

在HotSpot VM中內(nèi)嵌有兩個(gè)JIT編譯器,分別為 Client Compiler 和 Server Compiler盯拱,但大多數(shù)情況下我們簡(jiǎn)稱為C1編譯器和C2編譯器盒发。開發(fā)人員可以通過(guò)如下命令顯示指定 Java 虛擬機(jī)在運(yùn)行時(shí)到底使用哪一種即時(shí)編譯器

  • -client:指定 Java 虛擬機(jī)運(yùn)行在 Client模式下,并使用C1編譯器

    • C1編譯器會(huì)對(duì)字節(jié)碼進(jìn)行 簡(jiǎn)單和可靠的優(yōu)化狡逢,耗時(shí)短宁舰。以達(dá)到更快的編譯速度
  • -server:指定Java虛擬機(jī)運(yùn)行在 Server 模式下,并使用C2編譯器奢浑。

    • C2進(jìn)行耗時(shí)較長(zhǎng)的優(yōu)化蛮艰,以及激進(jìn)優(yōu)化。但優(yōu)化的代碼執(zhí)行效率更高
  • 分層編譯(Tiered Compilation)策略:程序解釋執(zhí)行(不開啟性能監(jiān)控)可以出發(fā)C1編譯雀彼,將字節(jié)碼編譯成機(jī)器碼壤蚜,可以進(jìn)行簡(jiǎn)單優(yōu)化即寡,也可以加上性能監(jiān)控,C2編譯會(huì)根據(jù)性能監(jiān)控信息進(jìn)行激進(jìn)優(yōu)化

  • Java7版本之后袜刷,默認(rèn)開啟分層編譯策略

C1和C2編譯器不同的優(yōu)化策略

  • C1編譯器上主要有方法內(nèi)聯(lián)聪富,去虛擬化、冗余消除

    • 方法內(nèi)聯(lián):將引用的函數(shù)代碼編譯到引用點(diǎn)處著蟹,這樣可以減少棧幀的生成墩蔓,減少參數(shù)傳遞以及跳轉(zhuǎn)過(guò)程
    • 去虛擬化:對(duì)唯一的實(shí)現(xiàn)類進(jìn)行內(nèi)聯(lián)
    • 冗余消除:在運(yùn)行期間把一些不會(huì)執(zhí)行的代碼折疊掉
  • C2的優(yōu)化主要是在全局層面,逃逸分析是優(yōu)化的基礎(chǔ)草则「峙。基于逃逸分析在C2上有如下優(yōu)化

    • 標(biāo)量替換:用標(biāo)量值替換聚合對(duì)象的屬性值
    • 棧上分配:對(duì)于未逃逸的對(duì)象分配對(duì)象在棧而不是堆
    • 同步消除:清除同步操作蟹漓,通常值synchronized
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末炕横,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子葡粒,更是在濱河造成了極大的恐慌份殿,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嗽交,死亡現(xiàn)場(chǎng)離奇詭異卿嘲,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)夫壁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門拾枣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人盒让,你說(shuō)我怎么就攤上這事梅肤。” “怎么了邑茄?”我有些...
    開封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵姨蝴,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我肺缕,道長(zhǎng)左医,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任同木,我火速辦了婚禮浮梢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘彤路。我一直安慰自己秕硝,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開白布斩萌。 她就那樣靜靜地躺著缝裤,像睡著了一般屏轰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上憋飞,一...
    開封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天霎苗,我揣著相機(jī)與錄音,去河邊找鬼榛做。 笑死唁盏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的检眯。 我是一名探鬼主播厘擂,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼锰瘸!你這毒婦竟也來(lái)了刽严?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤避凝,失蹤者是張志新(化名)和其女友劉穎舞萄,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體管削,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡倒脓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了含思。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片崎弃。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖含潘,靈堂內(nèi)的尸體忽然破棺而出饲做,到底是詐尸還是另有隱情,我是刑警寧澤调鬓,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布艇炎,位于F島的核電站,受9級(jí)特大地震影響腾窝,放射性物質(zhì)發(fā)生泄漏缀踪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一虹脯、第九天 我趴在偏房一處隱蔽的房頂上張望驴娃。 院中可真熱鬧,春花似錦循集、人聲如沸唇敞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)疆柔。三九已至咒精,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間旷档,已是汗流浹背模叙。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鞋屈,地道東北人范咨。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像厂庇,于是被迫代替她去往敵國(guó)和親渠啊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容