GitHub 2.6k Star 的Java工程師成神之路 ,不來了解一下嗎?前端
GitHub 2.6k Star 的Java工程師成神之路 ,真的不來了解一下嗎?java
GitHub 2.6k Star 的Java工程師成神之路 ,真的肯定不來了解一下嗎?git
在《Java代碼的編譯與反編譯》中,有過關於Java語言的編譯和反編譯的介紹。咱們能夠經過javac
命令將Java程序的源代碼編譯成Java字節碼,即咱們常說的class文件。這是咱們一般意義上理解的編譯。github
可是,字節碼並非機器語言,要想讓機器可以執行,還須要把字節碼翻譯成機器指令。這個過程是Java虛擬機作的,這個過程也叫編譯。是更深層次的編譯。後端
在編譯原理中,把源代碼翻譯成機器指令,通常要通過如下幾個重要步驟:數組
根據完成任務不一樣,能夠將編譯器的組成部分劃分爲前端(Front End)與後端(Back End)。緩存
前端編譯主要指與源語言有關但與目標機無關的部分,包括詞法分析、語法分析、語義分析與中間代碼生成。eclipse
後端編譯主要指與目標機有關的部分,包括代碼優化和目標代碼生成等。ide
咱們能夠把將.java
文件編譯成.class
的編譯過程稱之爲前端編譯。把將.class
文件翻譯成機器指令的編譯過程稱之爲後端編譯。優化
前端編譯主要指與源語言有關但與目標機無關的部分,包括詞法分析、語法分析、語義分析與中間代碼生成。
咱們所熟知的javac
的編譯就是前端編譯。除了這種之外,咱們使用的不少IDE,如eclipse,idea等,都內置了前端編譯器。主要功能就是把.java
代碼轉換成.class
代碼。
詞法分析階段是編譯過程的第一個階段。這個階段的任務是從左到右一個字符一個字符地讀入源程序,將字符序列轉換爲標記(token)序列的過程。這裏的標記是一個字符串,是構成源代碼的最小單位。在這個過程當中,詞法分析器還會對標記進行分類。
詞法分析器一般不會關心標記之間的關係(屬於語法分析的範疇),舉例來講:詞法分析器可以將括號識別爲標記,但並不保證括號是否匹配。
語法分析的任務是在詞法分析的基礎上將單詞序列組合成各種語法短語,如「程序」,「語句」,「表達式」等等.語法分析程序判斷源程序在結構上是否正確.源程序的結構由上下文無關文法描述。
語義分析是編譯過程的一個邏輯階段, 語義分析的任務是對結構上正確的源程序進行上下文有關性質的審查,進行類型審查。語義分析是審查源程序有無語義錯誤,爲代碼生成階段收集類型信息。
語義分析的一個重要部分就是類型檢查。好比不少語言要求數組下標必須爲整數,若是使用浮點數做爲下標,編譯器就必須報錯。再好比,不少語言容許某些類型轉換,稱爲自動類型轉換。
在源程序的語法分析和語義分析完成以後,不少編譯器生成一個明確的低級的或類機器語言的中間表示。該中間表示有兩個重要的性質: 1.易於生成; 2.可以輕鬆地翻譯爲目標機器上的語言。
在Java中,javac
執行的結果就是獲得一個字節碼,而這個字節碼其實就是一種中間代碼。
PS:著名的解語法糖操做,也是在javac中完成的。
首先,咱們你們都知道,一般經過 javac
將程序源代碼編譯,轉換成 java 字節碼,JVM 經過解釋字節碼將其翻譯成對應的機器指令,逐條讀入,逐條解釋翻譯。很顯然,通過解釋執行,其執行速度必然會比可執行的二進制字節碼程序慢不少。這就是傳統的JVM的**解釋器(Interpreter)**的功能。爲了解決這種效率問題,引入了 JIT 技術。
JAVA程序仍是經過解釋器進行解釋執行,當JVM發現某個方法或代碼塊運行特別頻繁的時候,就會認爲這是「熱點代碼」(Hot Spot Code)。而後JIT會把部分「熱點代碼」翻譯成本地機器相關的機器碼,並進行優化,而後再把翻譯後的機器碼緩存起來,以備下次使用。
HotSpot虛擬機中內置了兩個JIT編譯器:Client Complier和Server Complier,分別用在客戶端和服務端,目前主流的HotSpot虛擬機中默認是採用解釋器與其中一個編譯器直接配合的方式工做。
當 JVM 執行代碼時,它並不當即開始編譯代碼。首先,若是這段代碼自己在未來只會被執行一次,那麼從本質上看,編譯就是在浪費精力。由於將代碼翻譯成 java 字節碼相對於編譯這段代碼並執行代碼來講,要快不少。第二個緣由是最優化,當 JVM 執行某一方法或遍歷循環的次數越多,就會更加了解代碼結構,那麼 JVM 在編譯代碼的時候就作出相應的優化。
在機器上,執行java -version
命令就能夠看到本身安裝的JDK中JIT是哪一種模式:
上圖是個人機器上安裝的jdk1.8,能夠看到,他是Server Compile,可是,須要說明的是,不管是Client Complier仍是Server Complier,解釋器與編譯器的搭配使用方式都是混合模式,即上圖中的mixed mode。
上面咱們說過,要想觸發JIT,首先須要識別出熱點代碼。目前主要的熱點代碼識別方式是熱點探測(Hot Spot Detection),有如下兩種:
一、基於採樣的方式探測(Sample Based Hot Spot Detection) :週期性檢測各個線程的棧頂,發現某個方法常常出險在棧頂,就認爲是熱點方法。好處就是簡單,缺點就是沒法精確確認一個方法的熱度。容易受線程阻塞或別的緣由干擾熱點探測。
二、基於計數器的熱點探測(Counter Based Hot Spot Detection)。採用這種方法的虛擬機會爲每一個方法,甚至是代碼塊創建計數器,統計方法的執行次數,某個方法超過閥值就認爲是熱點方法,觸發JIT編譯。
在HotSpot虛擬機中使用的是第二種——基於計數器的熱點探測方法,所以它爲每一個方法準備了兩個計數器:方法調用計數器和回邊計數器。
方法計數器。顧名思義,就是記錄一個方法被調用次數的計數器。
回邊計數器。是記錄方法中的for或者while的運行次數的計數器。
前面提到過,JIT除了具備緩存的功能外,還會對代碼作各類優化。說到這裏,不得不佩服HotSpot的開發者,他們在JIT中對於代碼優化真的算是面面俱到了。
這裏簡答說起幾個我以爲比較重要的優化技術,並不許備直接展開,讀者感興趣的話,我後面再寫文章單獨介紹。
逃逸分析、 鎖消除、 鎖膨脹、 方法內聯、 空值檢查消除、 類型檢測消除、 公共子表達式消除