簡體   English   中英

為什么在使用 JIT 編譯器時 JVM 使用解釋器?

[英]Why Interpreter is used by JVM when JIT compiler is also used?

我們知道,JVM 同時使用解釋器和 JIT 編譯器。 JIT 編譯器將那些重復的字節碼轉換為機器碼並存儲在內存中。 現在,當解釋器逐行翻譯 ByteCode 並運行它時,它會簡單地跳過已經轉換並存儲在內存中的重復代碼的翻譯部分,但會直接運行它。 從而減少並發冗余翻譯。

那么為什么Java在JVM中使用解釋器呢? 像 JIT 這樣的編譯器可以一次完成將字節碼轉換為機器碼的全部任務嗎?

事實上,像 GraalVM 這樣的現代 Java 實現確實提供了將 Java 字節碼的整個類——甚至整個應用程序——編譯為本機代碼的選項,但提前,而不是在運行時。 實現 JIT 編譯器在運行時處理整個類當然是可能的,因此根本不需要解釋。

但是,在您有時間享用三道菜的餐點而 GraalVM 的本機代碼編譯器完成這些工作之后,很容易理解為什么批量預編譯不是JVM 中的默認編譯機制。 編譯為本機代碼可能會很慢,而且 Java 並不是一種天生可編譯的語言。

大多數 JVM 提供某種形式的自適應解釋/編譯平衡,在運行時實現。 對於重復很多的代碼段,解釋是“慢”的,因為解釋的工作要重復很多次。 對於只執行一次的代碼,編譯是“慢”的,因為編譯工作必須在任何程序指令實際執行之前完成。

所以現代 Java 實現提供了這兩種策略,並試圖平衡它們以在運行時獲得最佳的整體性能。 從廣義上講,我們想要做的是(JIT)只編譯應用程序中那些編譯時間成本最能被它帶來的好處抵消的部分。 如何做到這一點一直是大量研究的主題,並且不斷開發新的方法。

這個答案中有一個很好的比較,它讓我清楚為什么 Java 同時使用 AOT 和 JIT。

這里提到的 JIT 的“微調”是在 JVM 的編譯器中完成的,它針對它運行的每個系統進行了優化。 而且您沒有考慮鏈接中列出的缺點。

JRockit JVM 沒有解釋器。 它編譯所有字節碼,即使在進行調試時也是如此,因此沒有必要。

解釋器的一個好處是啟動速度更快。 例如,靜態初始化程序只執行一次,因此通常很少需要編譯它。

並非所有 JVM 實現都采用解釋器和 JIT 編譯器的組合。 有些只有解釋器,有些只有一兩個 JIT 編譯器。

最著名的 JVM HotSpot JVM 確實有兩個解釋器和 JIT 兩個編譯器:

  • 用可移植 C++ 編寫的解釋器。 優點是你的系統上只需要一個 C++ 編譯器來運行這個解釋器
  • 用某種匯編語言編寫的“模板化”解釋器。 這個解釋器依賴於架構。
  • 客戶端編譯器:編譯速度快,代碼效率低
  • 服務器編譯器:編譯速度較慢,代碼高度優化

根據您的系統或您配置 HotSpot 的方式,它將包含 C++ 解釋器或模板化的解釋器,這兩者不能組合(afaik)。

這里我們有解釋的第一個優勢:它更便攜。 有一個用於許多硬件/操作系統組合的 C++ 編譯器。 JIT 編譯器生成機器代碼,因此必須分別移植到每個支持的體系結構。

另一個優勢是啟動時間。 JIT 編譯需要時間,但解釋器可以立即開始執行代碼。 此外,JIT 編譯器可以在解釋代碼的同時在后台運行。

JIT 編譯器不僅可以在解釋器運行時進行編譯,而且還可以生成跳轉回解釋器的代碼。 這意味着 JIT 編譯器不必支持所有功能/角落情況(無論出於何種原因)。 如果遇到無法編譯的內容,它可以從編譯后的代碼生成一個跳轉到解釋器的跳轉,或者它甚至可以完全放棄編譯該代碼——這很好(在某種意義上),因為它仍然可以被解釋。

在如此復雜的系統中為某些方法提供確鑿的證據是非常困難的。 一個數據點可能是,其他被認為是最先進的虛擬機采用了類似的解釋器和兩個編譯器的方法:V8 和 SpiderMonkey JavaScript 虛擬機。

OP 還詢問為什么不提前編譯所有內容。 首先,這可以通過 GraalVM 原生鏡像來完成,並且還有一些其他類似的技術。 其次,不提前編譯有一些優點:您可以在編譯之前運行代碼一段時間意味着您可以觀察它的行為並更精確地針對 JIT 編譯器中的優化(this 的 else 分支)如果從未執行過 - 不要為它浪費內聯預算)並且因為您可以跳轉到解釋器,您還可以進行“推測”優化(甚至不用費心編譯 else 分支),如果推測失敗,則代碼跳回解釋器。 然而,這個方案不需要解釋器。 只需一個可以從一個編譯(更優化)跳轉到另一個(更通用)的 JIT 編譯器就可以了。 JRockit 做到了(afaik)。

解釋器允許即時運行和調試代碼。 編譯器必須預編譯才能運行,這意味着如果您的首選環境沒有發現錯誤,則需要您進行可能的修復並重新編譯整個項目

因此,它同時具有解釋器和編譯器,以允許編譯器的速度,並且仍然允許開發人員通過進行小的更改來即時調試並檢查修復程序,而無需每次重新編譯整個項目。

簡而言之,最大的原因就是這個。
編譯器是為最終用戶運行最快方式
解釋器開發人員調試和編碼最快方式

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM