執行過程+執行效率
摘要:
將class檔案載入到JVM中,載入後的Java類會被存放在 方法區 ,實際執行時,虛擬機器會執行方法區內的程式碼
JVM同樣會將記憶體劃分出 堆 和 棧 來儲存執行時資料,棧會細分 本地方法棧 和 Java方法棧
PC暫存器:用於記錄 各個執行緒的執行...
- 將class檔案載入到JVM中,載入後的Java類會被存放在 方法區 ,實際執行時,虛擬機器會執行方法區內的程式碼
- JVM同樣會將記憶體劃分出 堆 和 棧 來儲存執行時資料,棧會細分 本地方法棧 和 Java方法棧
- PC暫存器:用於記錄 各個執行緒的執行位置
- 在執行過程中,每當呼叫進入一個 Java方法 ,JVM會在 當前執行緒的Java方法棧 中生成一個 棧幀
- 棧幀用於存放 區域性變量表 和 運算元
- 棧幀的大小是 提前計算 好的,並且JVM 不要求 棧幀在記憶體空間裡 連續分佈
- 當退出當前執行的方法時,不管是 正常返回 還是 異常返回 ,JVM都會 彈出並捨棄當前執行緒的當前棧幀
硬體視角
- Java位元組碼無法直接執行,需要JVM將位元組碼翻譯成機器碼,有兩種形式: 解析執行 + 即時編譯
- 解釋執行:逐條將位元組碼翻譯成機器碼並執行, 無需等待編譯
- 即時編譯(JIT):將 一個方法中包含的所有位元組碼 編譯成機器碼後再執行, 實際執行速度更快
- HotSpot預設採用 混合模式 , 先解析執行 位元組碼,然後將其反覆執行的熱點程式碼, 以方法為單位 進行 即時編譯
- 即時編譯建立在 2-8定律 的假設之上
- 對於佔據大部分的不常用程式碼,無需耗費時間將其編譯成機器碼,而是採用解釋執行的方式
- 對於僅佔小部分的熱點程式碼,我們可以將其編譯成機器碼,以達到理想的執行速度
JVM的執行效率
- 理論上講,即時編譯後的Java程式的執行效率,是有可能超過C++程式的,這是因為與靜態編譯相比,即時編譯擁有程式的 執行時資訊 ,並且能夠根據這個資訊作出 相應的優化
- 為了滿足不同使用者場景的需要,HotSpot內建了多個即時編譯器: C1 、 C2 和 Graal (Java 10引入,實驗性)
- 引入多個即時編譯器,是為了在 編譯時間 和 生成程式碼的執行效率 之間進行取捨
- C1又叫做 Client編譯器 ,面向對 啟動效能 有要求的GUI程式,採用的優化手段相對簡單,因此編譯時間較短
- C2又叫做 Server編譯器 ,面向對是對 峰值效能 有要求的服務端程式,採用的優化手段相對複雜,因此編譯時間較長,但生成程式碼執行效率較高
- 從Java 7開始,HotSpot預設採用 分層編譯 的方式, 熱點方法首先會被C1編譯,而後熱點方法中的熱點會進一步被C2編譯
- 為了不干擾應用的正常執行,HotSpot的即時編譯是放在 額外的編譯執行緒 中進行的,HotSpot會根據CPU的數量設定編譯執行緒的數目,預設按 1:2 的比例配置給C1和C2編譯器
- 在計算資源充足的情況下,位元組碼的 解釋執行和即時編譯可同時進行 。解析完成後的機器碼會在 下一次呼叫 該方法時啟用,以替換原本的解釋執行