(二)Java 虛擬機具體是怎樣運行 Java 字節碼的?

Write Once,Run Anywhere

Java 祖師爺就是由於發現用 C++ 開發的過程中會花大量的時間處理內存、不同的指令架構等的問題,所以纔有高“移植性”的Java 誕生。採訪Java 祖師爺的報道鏈接 。

 And  there are a bunch of places in C, where it’s really easy to make errors that can cause your system to fall over and just do bad things. Most of them have to do with the memory model. The two big ones we have, three big ones I guess were the unchecked array bounds, the weird and wonderful world of pointers and then the fact that you can cast anything to anything and they’re always completely unchecked.

And  when these consumer electronics companies, to look through the things that caused them reliability issues; those were like nearly at the top. And so, it’s like well okay, so, I was the person in the project who was tasked with, well go off and try to figure out how to fix these problems. And I did and it started out as just take C++ and try to fix it, but then it got like further and further out of control as other issues popped in.

So, like one of the interesting issues for a lot of these companies was that they really hated the way that they got tied to particular processor architectures.  that once you made a decision to go with like an Intel Architecture machine or any other particular architecture, then you were just because of the toolchain you were tied with that architecture for life. And so, you couldn’t  for whatever business reasons would crop up, you couldn’t change your mind. And that they found deeply disturbing. So, the oak really started from IOT, or at least what was now called IOT.

 

Java 程序執行過程的兩種視角

通過編譯器將 Java 程序轉換成該虛擬機所能識別的指令序列,稱 Java 字節碼 (是因爲 Java 字節碼指令的操作碼被固定爲一個字節

從虛擬機[HotSpot] 視角來看,執行 Java 代碼首先需要將它編譯而成的 class 文件(特定順序結構的字節碼)加載到 Java 虛擬機中,加載後的 Java 類信息會被存放於元空間中。實際運行時,虛擬機會執行其中的指令。

在運行過程中,每當調用進入一個 Java 方法,Java 虛擬機會在當前線程的 Java 方法棧中生成一個棧幀,用以存放局部變量以及字節碼的操作數。這個棧幀的大小是提前計算好的,而且 Java 虛擬機不要求棧幀在內存空間裏連續分佈。

從硬件視角來看,Java 字節碼無法直接執行。因此,Java 虛擬機需要將字節碼翻譯成目標機器碼。在 HotSpot 裏面,上述翻譯過程有兩種形式:第一種是解釋執行,即逐條將字節碼翻譯成機器碼並執行 [在解釋執行過程中,每當爲 Java 方法分配棧楨時,Java 虛擬機往往需要開闢一塊額外的空間作爲操作數棧,來存放計算的操作數以及返回結果];第二種是即時編譯(Just-In-Time compilation,JIT),即將一個方法中包含的所有字節碼編譯成機器碼後再執行。

前者的優勢在於無需等待編譯,而後者的優勢在於實際運行速度更快。HotSpot 默認採用混合模式,綜合瞭解釋執行和即時編譯兩者的優點。它會先解釋執行字節碼,而後將其中反覆執行的熱點代碼,以方法爲單位進行即時編譯。

爲了滿足不同用戶場景的需要,HotSpot 內置了多個即時編譯器:C1、C2 和 Graal。Graal 是 Java 10 正式引入的實驗性即時編譯器。HotSpot 裝載了多個不同的即時編譯器,以便在編譯時間和生成代碼的執行效率之間做取捨。其中,C1 又叫做 Client 編譯器,面向的是對啓動性能有要求的客戶端 GUI 程序,採用的優化手段相對簡單,因此編譯時間較短。C2 又叫做 Server 編譯器,面向的是對峯值性能有要求的服務器端程序,採用的優化手段相對複雜,因此編譯時間較長,但同時生成代碼的執行效率較高。

從 Java 7 開始,HotSpot 默認採用分層編譯的方式:熱點方法首先會被 C1 編譯,而後熱點方法中的熱點會進一步被 C2 編譯。爲了不干擾應用的正常運行,HotSpot 的即時編譯是放在額外的編譯線程中進行的。

HotSpot 會根據 CPU 的數量設置編譯線程的數目,並且按 1:2 的比例配置給 C1 及 C2 編譯器。(沒找到出處,評論去老師回覆的)默認的分層編譯應該是達到兩千調C1,達到一萬五調C2。

P.S. 本系列文章爲學習出自鄭雨迪的《深入拆解 Java 虛擬機》課程整理筆記。購買請掃描下方二維碼:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章