深入理解JVM - JVM編譯器

編譯器類型

編譯器最終的目的是將我們寫的源代碼編譯成機器能識別的機器碼。 在JVM 中有三個非常重要的編譯器,它們分別是:前端編譯器、JIT 編譯器和AOT編譯器。

前端編譯器

將源代碼轉化成字節碼,如javac;我們一般稱 javac 編譯器為前端編譯器,因為其發生在整個編譯的前期。javac編譯過程大致可以分為1個準備過程和3個處理過程,它們分別如下所示。

  1. 準備過程:初始化插入式注解處理器,java是支持注解的。
  2. 解析與填充符號表過程,包括:
    a. 詞法、語法分析。將源代碼的字符流轉變為標記集合,構造出抽象語法樹。
    b. 填充符號表。產生符號地址和符號信息。
  3. 插入式注解處理器的注解處理過程:插入式注解處理器的執行階段,本章的實戰部分會設計一個插入式注解處理器來影響Javac的編譯行為。
  4. 分析與字節碼生成過程,包括:
    a. 標注檢查。對語法的靜態信息進行檢查。
    b. 數據流及控制流分析。對程序動態運行過程進行檢查。
    c. 解語法糖。將簡化代碼編寫的語法糖還原為原有的形式。
    d. 字節碼生成。將前面各個步驟所生成的信息轉化成字節碼。

JIT編譯器(即時編譯器)

將字節碼轉換成機器碼,如HotSpot VM的C1和C2編譯器。

當源代碼轉化為字節碼之后,程序要運行程序,有兩種選擇:一種是使用 Java 解釋器解釋執行字節碼,另一種則是使用編譯器將字節碼轉化為本地機器代碼。

  • 解釋器執行:將編譯好的字節碼一行一行地翻譯為機器碼執行,程序啟動速度快,但是運行速度慢;
  • 編譯器執行:以方法為單位,將字節碼一次性翻譯為機器碼后執行,程序啟動速度慢,但是運行速度快。

在整個Java虛擬機執行架構里,解釋器與編譯器經常是相輔相成地配合工作,當虛擬機發行某個方法執行特別頻繁時,就會把這些代碼判定成“熱點代碼”,為了提高熱點代碼的執行效率,在運行時,虛擬機將會把這些代碼編譯成本地機器碼,并以各種手段盡可能地進行代碼優化,運行時完成這個任務的后端編譯器被稱為即時編譯器。當執行JIT編譯后的機器碼出現問題時,那么虛擬機又會使用解釋器來執行代碼。

在 HotSpot 虛擬機內置了多個即時編譯器,分別稱為 Client 編譯器(C1)、Server 編譯器(C2)和graal編譯器。

  • C1:即Client編譯器,面向對啟動性能有要求的客戶端GUI程序,將字節碼轉換為機器碼時只進行簡單、可靠的優化,因此編譯的時間較短,通過-client參數打開。
  • C2:即Server編譯器,面向對性能峰值有要求的服務端程序,將字節碼轉換為機器碼時會進行激進、復雜的優化,因此編譯時間長,但是在運行過程中性能更好,通過-server參數打開。
  • graal:graal是JDK10引入的一個編譯器,目的是用來替換C2編譯器。

虛擬機執行模式

虛擬機有三種執行模式:混合模式(Mixed Mode)、解釋模式(Interpreted Mode)和編譯模式(CompiledMode),默認是混合模式。

  • 混合模式(Mixed Mode):解釋器與編譯器搭配使用的方式在虛擬機中被稱為“混合模式”(Mixed Mode)。
  • -Xint:指定虛擬機使用“解釋模式”(Interpreted Mode),代碼都使用解釋方式執行;
  • -Xcomp:指定虛擬機使用“編譯模式”,代碼優先采用編譯方式執行程序,但是當編譯后的代碼無法正常執行時,這時使用解釋執行來兜底;

編譯器優化

為了在程序啟動響應速度與運行效率之間達到最佳平衡,HotSpot虛擬機在編譯子系統中加入了分層編譯的功能,分層編譯根據編譯器編譯、優化的規模與耗時,劃分出不同的編譯層次,其中包括:

  • 第0層:程序只使用解釋執行,并且解釋器不開啟性能監控功能(Profiling)。
  • 第1層:使用客戶端編譯器將字節碼編譯為本地代碼來運行,進行簡單可靠的穩定優化,不開啟性能監控功能。
  • 第2層:仍然使用客戶端編譯器執行,僅開啟方法及回邊次數統計等有限的性能監控功能。
  • 第3層:仍然使用客戶端編譯器執行,開啟全部性能監控,除了第2層的統計信息外,還會收集如分支跳轉、虛方法調用版本等全部的統計信息。
  • 第4層:使用服務端編譯器將字節碼編譯為本地代碼,相比起客戶端編譯器,服務端編譯器會啟用更多編譯耗時更長的優化,還會根據性能監控信息進行一些不可靠的激進優化。

以上層次并不是固定不變的,根據不同的運行參數和版本,虛擬機可以調整分層的數量。分層編譯的交互關系,如下:

image.png

-XX:+TieredCompilation,開啟分層編譯,可以讓jvm在啟動時啟用client編譯,隨著代碼變熱后再轉為server編譯。

熱點探測

對于程序來說,通常只有一部分代碼被經常執行,這些關鍵代碼被稱為應用的熱點,執行的越多就認為是越熱,將這些代碼編譯為本地機器特定的二進制碼,可以有效提高應用性能。目前主流的熱點探測判定方式有兩種,分別是:

  • 基于采樣的熱點探測(Sample Based Hot Spot Code Detection)。采用這種方法的虛擬機會周期性地檢查各個線程的調用棧頂,如果發現某個(或某些)方法經常出現在棧頂,那這個方法就是“熱點方法”。基于采樣的熱點探測的好處是實現簡單高效,還可以很容易地獲取方法調用關系(將調用堆棧展開即可),缺點是很難精確地確認一個方法的熱度,容易因為受到線程阻塞或別的外界因素的影響而擾亂熱點探測。
  • 基于計數器的熱點探測(Counter Based Hot Spot Code Detection)。采用這種方法的虛擬機會為每個方法(甚至是代碼塊)建立計數器,統計方法的執行次數,如果執行次數超過一定的閾值就認為它是“熱點方法”。這種統計方法實現起來要麻煩一些,需要為每個方法建立并維護計數器,而且不能直接獲取到方法的調用關系。但是它的統計結果相對來說更加精確嚴謹。

AOT編譯器

將源代碼直接編譯成機器碼,稱為提前編譯器(AOT編譯器),如:Jaotc;

提前編譯器主要的優點:

  • 提前編譯器不會占用程序的運行時間和運算資源,但是及時編譯器會,這也是即時編譯器的最大弱點。
  • 可以作為即時編譯器的緩存,改善程序的啟動時間。

提前編譯器主要的缺點,也是即時編譯器的優點:

  • 不能進行性能分析制導優化(Profile-Guided Optimization,PGO),因為提前編譯不能收集到程序的運行時監控數據,無法定位熱點代碼,所以不能集中優化和分配更好的資源進行制導優化。
  • 不能進行激進預測性優化,因為提前編譯器編器必須保證優化后的程序一定能正常運行,所以不能進行一些激進優化。
  • 不能進行鏈接時優化(Link-Time Optimization,LTO),因為主程序與動態鏈接庫的代碼在它們編譯時是完全獨立的,兩者各自編譯、優化自己的代碼,所以提前編譯器無法進行鏈接時優化,但是程序運行時會將所有的Class加載到虛擬機中,所以即時編譯器可以進行鏈接時優化

總結

從應用啟動速度來看:解釋執行 > AOT 編譯器 > JIT 編譯器。
從應用運行速度來看: JIT 編譯器> AOT 編譯器 > 解釋執行。

JVM虛擬為了保持程序啟動時間和運行效率的平衡,一般會使用多種方式配合工作。

參考

《深入理解JAVA虛擬機》

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,106評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,441評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,211評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,736評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,475評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,834評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,829評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,009評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,559評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,306評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,516評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,038評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,728評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,132評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,443評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,249評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,484評論 2 379

推薦閱讀更多精彩內容

  • 《深入理解Java虛擬機》筆記_第一遍 先取看完這本書(JVM)后必須掌握的部分。 第一部分 走近 Java 從傳...
    xiaogmail閱讀 5,136評論 1 34
  • 第二部分 自動內存管理機制 第二章 java內存異常與內存溢出異常 運行數據區域 程序計數器:當前線程所執行的字節...
    小明oh閱讀 1,197評論 0 2
  • Java 虛擬機屏蔽了與具體操作系統平臺相關的信息,使得 Java 語言編譯程序只需生成在 Java 虛擬機上運行...
    尋夢的尕柳閱讀 873評論 0 11
  • 他是火, 我是蛾, 我怕死。
    豈言豈弟閱讀 269評論 0 1
  • 2013年6月底大學畢業后她從沈陽來到北京,成為一名程序猿,而我從邯鄲出發一路向東,在濰坊一家環保公司任職污...
    Yangcei閱讀 232評論 0 2