Java類編譯、加載、和執行機制


Java類編譯、加載、和執行機制

標簽: java 類加載 類編譯 類執行 機制


0.前言

個人認為,對於JVM的理解,主要是兩大方面內容:

  • Java類的編譯、加載和執行。
  • JVM的內存管理和垃圾回收機制。

本文主要是以概要的形式學習第一點:類的編譯、加載和執行。關於內存管理機制請看另外一篇文章JVM的內存管理和垃圾回收機制


1. Java類的編譯過程

這是由*.java源碼文件轉為 .class二進制字節碼文件的過程。
我們編寫好的源代碼,就是
.java文件。使用“javac test.java”就可以編譯test.java文件。

編譯過程主要有三步:

  • 詞法分析和輸入到符號表
  • 注解處理
  • 語義分析和生成字節碼

詳細過程:

源代碼文件*.java -> 詞法分析器 -> tokens流 -> 語法分析器 -> 語法樹/抽象語法樹 -> 語義分析器 -> 注解抽象語法樹 -> 字節碼生成器 -> JVM字節碼文件*.class 

最后剩成的JVM字節碼文件,使用命令“javap -c test”可以查看test.class的字節碼信息,主要包含三項內容:

  • 結構信息:class文件相關信息。

  • 元數據:Java源碼中的聲明和常量信息。

  • 方法信息:Java源碼語句和表達式對應的字節碼。


2. 類加載機制

2.1 類加載器分類

類加載器其實也是Java類。有四大類:

  • 根加載器Bootstrap Class Loader

  • 擴展加載器Extension Class Loader

  • 系統應用加載器APP Class Loader

  • 用戶自定義加載器Customer Class Loader

下面是各個類加載器的具體情況:

類加載器分類

Java程序在執行前先要檢查類是否已經被加載。

2.2檢查過程

檢查類是否已經被加載,從底層往上層依次檢查各個加載器已經加載的類,順序是系統應用類加載器、擴展加載器、根加載器,一旦發現被某個加載器加載過,則馬上使用該類。如果一直找到最頂層的根加載器,發現類還沒有被加載進JVM運行數據區的方法區,則接下來就要加載該類。

2.3類加載過程

加載過程和檢查過程順序相反,從上層往下層的順序進行加載。從加載器檢查自己的加載路徑,找要加載的類,一旦找到類就進行加載。

注意:對每個加載器,最多只能加載一次系統絕對路徑下的同一個類。對類而言,可以被不同加載器重復加載,只要你把類放到類加載器的加載路徑下,就可以被那個加載器加載。


3. 類執行機制

類在被加載之后,接下來進行連接、初始化,然后才是使用,最后卸載。

3.1 連接

連接(linking)包括三個部分:

  • 驗證verifying:驗證類符合Java規范和JVM規范,和編譯階段的語法語義分析不同。

  • 准備preparing:為類的靜態變量分配內存,初始化為系統的初始值。(不初始化靜態代碼塊)。對於final static修飾的變量,直接賦值為用戶的定義值。

  • 解析resolving:將符號引用(字面量描述)轉為直接引用(對象和實例的地址指針、實例變量和方法的偏移量)

3.2 類初始化

初始化類的靜態變量和靜態代碼塊為用戶自定義的值。非靜態類在實例化類,在Java堆中創建對象的時候,才會進行初始化。初始化的順序,和Java源碼的從上到下順序一致。注意:什么時候觸發初始化?在類被Java程序“第一次主動使用”的時候,才會觸發初始化操作(如果還沒有加載,則會順勢觸發類的加載過程)。

類初始化

3.3內存分配

啟動JVM后,操作系統就給JVM分配了內存空間,JVM自己由把得到的內存分為幾塊:
JVM內存分配情況

JVM是基於棧結構的體系結構來執行class字節碼的,不同於windows和Linux基於寄存器結構。類的執行機制,主要是在Java棧上面完成。當一個線程被創建后,Java棧和PC寄存器就會被創建。Java棧由棧幀組成,調用一個方法,就會生成一個棧幀(可以理解為表示調用一個方法)。棧幀又由局部變量表、操作數棧和常量池引用組成。
棧幀結構

執行的時候,每個線程都有一個Java棧,當前執行的棧稱為當前棧。一個Java棧調用多個方法,則會push很多個棧幀,當前活動的棧幀稱為當前棧幀。當前棧幀執行完畢之后,會把執行結果(如果有)壓入到調用它的那個棧幀的操作數棧中,作為上一個棧幀的一個中間處理結果被調用,然后就會被pop出去。當所有調用的方法執行結束后,棧幀也就都pop掉沒有了。
例如:執行代碼
操作數棧執行過程演示

3.4 類具體的執行過程

本步驟由執行引擎Execute Engine來完成。執行引擎把字節碼轉為機器碼,然后操作系統才可以真正調用,在硬件環境上執行代碼。執行引擎的通過Java字節碼解釋器(一行一行解釋字節碼)和JIT(Just In Time)即時編譯器(對熱代碼整段編譯)來完成機器碼的翻譯工作。

JIT編譯器的工作流程為:

JVM字節碼 -> 機器無關優化 -> 中間代碼 -> 機器相關優化 -> 中間代碼 -> 寄存器分配器 -> 中間代碼 -> 目標機器碼生成器 -> 目標機器碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM