Java程序到底是如何執行的

項目推薦: Spring Cloud 、Spring Security OAuth2的RBAC權限管理系統 歡迎關注

最近裸辭,好好歇歇。整理面試題,歡迎關注。

Java 程序執行過程

無論是使用開發工具IDEA Eclipse 還是使用容器 Tomcat jetty, Java 程序的執行流程如下:

  1. Java 代碼編譯成字節碼, 從文件後綴來看.java編譯成.class 類型的文件;
  2. class 文件放置到 Java 虛擬機,這個虛擬機通常指的是 Oracle 官方自帶的 Hotspot JVM;
  3. Java 虛擬機使用類加載器 Class Loader 裝載 class 文件;
  4. 加載完成之後,會進行字節碼校驗,字節碼校驗通過之後 JVM 解釋器會把字節碼翻譯成機器碼交由操作系統執行。

類加載器

簡單來說,加載指的是把class字節碼文件從各個來源通過類加載器裝載入內存中。

這裏有兩個來源:

  • 字節碼來源。一般的加載來源包括從本地路徑下編譯生成的.class文件,從jar包中的.class文件
  • 動態代理實時編譯類加載器。一般包括啓動類加載器,擴展類加載器,應用類加載器,以及用戶的自定義類加載器。

注:爲什麼會有自定義類加載器?

一方面是由於java代碼很容易被反編譯,如果需要對自己的代碼加密的話,可以對編譯後的代碼進行加密,然後再通過實現自己的自定義類加載器進行解密,最後再加載。
另一方面也有可能從非標準的來源加載代碼,比如從網絡來源,那就需要自己實現一個類加載器,從指定源進行加載。

(上圖)這種層次關係稱爲類加載器的雙親委派模型。雙親委派模型的工作流程是:如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把請求委託給父加載器去完成,依次向上,因此,所有的類加載請求最終都應該被傳遞到頂層的啓動類加載器中,只有當父加載器在它的搜索範圍中沒有找到所需的類時,即無法完成該加載,子加載器纔會嘗試自己去加載該類。

驗證

主要是爲了保證加載進來的字節流符合JVM規範。對於字節碼的驗證,保證程序語義的合理性,比如要保證類型轉換的合理性。對於符號引用的驗證,比如校驗符號引用中通過全限定名是否能夠找到對應的類?校驗符號引用中的訪問性(private,public等)是否可被當前類訪問?

準備

主要是爲類變量分配內存,賦初始值。特別需要注意,初值,不是代碼中具體寫的初始化的值,而是Java虛擬機根據不同變量類型的默認初始值。比如8種基本類型的初值,默認爲0;引用類型的初值則爲null;常量的初值即爲代碼中設置的值,final static tmp = 123, 那麼該階段tmp的初值就是123

解析

將常量池內的符號引用替換爲直接引用的過程。在解析階段,虛擬機會把所有的類名,方法名,字段名這些符號引用替換爲具體的內存地址或偏移量,也就是直接引用。

初始化

這個階段主要是對類變量初始化,執行類構造器。

JIT觸發標準

在 HotSpot 虛擬機中,熱點探測 是 JIT 的觸發標準。

基於採樣的熱點判定

主要是虛擬機會週期性的檢查各個線程的棧頂,若某個或某些方法經常出現在棧頂,那這個方法就是“熱點方法”。這種判定方式的優點是實現簡單;缺點是很難精確一個方法的熱度,容易受到線程阻塞或外界因素的影響。
熱點探測是基於計數器的熱點探測,採用這種方法的虛擬機會爲每個方法建立計數器統計方法的執行次數,如果執行次數超過一定的閾值就認爲它是“熱點方法” 。

基於計數器的熱點判斷

虛擬機運行時候,當計數器超過閾值溢出了,就會觸發 JIT 編譯,JIT 編譯器就會將這段代碼編譯成機器語言並緩存,在該循環時間段內,會直接將執行代碼替換,執行緩存的機器語言。

  • 方法調用計數器

方法調用計數器用於統計方法被調用的次數,默認閾值在 client 模式下是 1500 次,在 server 模式在是 10000 次,可通過-XX: CompileThreshold來設定;

  • 回邊計數器

回邊計數器用於統計的是方法中循環體代碼執行的次數。 默認閾值在 client 默認爲 13995,server 默認爲 10700,可通過 -XX: OnStackReplacePercentage=N來設置;

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