## 引入
我們可以通過javac命令將Java程序的**源代碼**編譯成**Java字節碼**,即我們常說的class文件。這是我們通常意義上理解的編譯。
但是,字節碼并不是機器語言,要想讓機器能夠執行,還需要把字節碼翻譯成**機器指令**。這個過程是Java虛擬機做的,這個過程也叫編譯。是更深層次的編譯。
在編譯原理中,把源代碼翻譯成機器指令,一般要經過以下幾個重要步驟:

根據完成任務不同,可以將編譯器的組成部分劃分為前端(Front End)與后端(Back End)。
* 前端編譯主要指與源語言有關但與目標機無關的部分,包括詞法分析、語法分析、語義分析與中間代碼生成。
* 后端編譯主要指與目標機有關的部分,包括代碼優化和目標代碼生成等。
我們可以把將.java文件編譯成.class的編譯過程稱之為**前端編譯**。把將.class文件翻譯成機器指令的編譯過程稱之為**后端編譯**。
## Java中的前端編譯
前端編譯主要指與源語言有關但與目標機無關的部分,包括**詞法分析、語法分析、語義分析與中間代碼生成**。
我們所熟知的javac的編譯就是前端編譯。除了這種以外,我們使用的很多**IDE**,如eclipse,idea等,都內置了前端編譯器。主要功能就是把.java代碼轉換成.class代碼。
### 詞法分析
詞法分析階段是編譯過程的第一個階段。這個階段的任務是從左到右一個字符一個字符地讀入源程序,**將字符序列轉換為標記(token)序列的過程**。這里的標記是一個字符串,是構成源代碼的最小單位。在這個過程中,詞法分析器還會對標記進行分類。
詞法分析器通常不會關心標記之間的關系(屬于語法分析的范疇),舉例來說:詞法分析器能夠將括號識別為標記,但并不保證括號是否匹配。
### 語法分析
語法分析的任務是在詞法分析的基礎上將單詞序列組合成各類語法短語,如“程序”,“語句”,“表達式”等等.語法分析程序**判斷源程序在結構上是否正確**。源程序的結構由上下文無關文法描述。
### 語義分析
語義分析是編譯過程的一個邏輯階段, 語義分析的任務是對結構上正確的源程序進行上下文有關性質的審查,進行類型審查。語義分析是**審查源程序有無語義錯誤**,為代碼生成階段收集類型信息。
語義分析的一個重要部分就是**類型檢查**。比如很多語言要求數組下標必須為整數,如果使用浮點數作為下標,編譯器就必須報錯。再比如,很多語言允許某些類型轉換,稱為自動類型轉換。
### 中間代碼生成
在源程序的語法分析和語義分析完成之后,很多編譯器生成一個明確的低級的或類機器語言的中間表示。該中間表示有兩個重要的性質: 1.易于生成; 2.能夠輕松地翻譯為目標機器上的語言。
在Java中,**javac執行的結果就是得到一個字節碼,而這個字節碼其實就是一種中間代碼**。
PS:著名的解語法糖操作,也是在javac中完成的。
## Java中的后端編譯
首先,我們大家都知道,通常通過 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),有以下兩種:
* 1、基于采樣的方式探測(Sample Based Hot Spot Detection) :周期性檢測各個線程的棧頂,發現某個方法經常出險在棧頂,就認為是熱點方法。好處就是簡單,缺點就是無法精確確認一個方法的熱度。容易受線程阻塞或別的原因干擾熱點探測。
* 2、基于計數器的熱點探測(Counter Based Hot Spot Detection)。采用這種方法的虛擬機會為每個方法,甚至是代碼塊建立計數器,統計方法的執行次數,某個方法超過閥值就認為是熱點方法,觸發JIT編譯。
在HotSpot虛擬機中使用的是第二種——**基于計數器的熱點探測方法**,因此它為每個方法準備了兩個計數器:方法調用計數器和回邊計數器。
* 方法計數器。顧名思義,就是記錄一個方法被調用次數的計數器。
* 回邊計數器。是記錄方法中的for或者while的運行次數的計數器。
### 編譯優化
前面提到過,JIT除了具有緩存的功能外,還會對代碼做各種優化。說到這里,不得不佩服HotSpot的開發者,他們在JIT中對于代碼優化真的算是面面俱到了。
- java
- 設計模式
- 設計模式總覽
- 設計原則
- 工廠方法模式
- 抽象工廠模式
- 單例模式
- 建造者模式
- 原型模式
- 適配器模式
- 裝飾者模式
- 代理模式
- 外觀模式
- 橋接模式
- 組合模式
- 享元模式
- 策略模式
- 模板方法模式
- 觀察者模式
- 迭代子模式
- 責任鏈模式
- 命令模式
- 備忘錄模式
- 狀態模式
- 訪問者模式
- 中介者模式
- 解釋器模式
- 附錄
- JVM相關
- JVM內存結構
- Java虛擬機的內存組成以及堆內存介紹
- Java堆和棧
- 附錄-數據結構的堆棧和內存分配的堆區棧區的區別
- Java內存之Java 堆
- Java內存之虛擬機和內存區域概述
- Java 內存之方法區和運行時常量池
- Java 內存之直接內存(堆外內存)
- JAVA內存模型
- Java內存模型介紹
- 內存模型如何解決緩存一致性問題
- 深入理解Java內存模型——基礎
- 深入理解Java內存模型——重排序
- 深入理解Java內存模型——順序一致性
- 深入理解Java內存模型——volatile
- 深入理解Java內存模型——鎖
- 深入理解Java內存模型——final
- 深入理解Java內存模型——總結
- 內存可見性
- JAVA對象模型
- JVM內存結構 VS Java內存模型 VS Java對象模型
- Java的對象模型
- Java的對象頭
- HotSpot虛擬機
- HotSpot虛擬機對象探秘
- 深入分析Java的編譯原理
- Java虛擬機的鎖優化技術
- 對象和數組并不是都在堆上分配內存的
- 垃圾回收
- JVM內存管理及垃圾回收
- JVM 垃圾回收器工作原理及使用實例介紹
- JVM內存回收理論與實現(對象存活的判定)
- JVM參數及調優
- CMS GC日志分析
- JVM實用參數(一)JVM類型以及編譯器模式
- JVM實用參數(二)參數分類和即時(JIT)編譯器診斷
- JVM實用參數(三)打印所有XX參數及值
- JVM實用參數(四)內存調優
- JVM實用參數(五)新生代垃圾回收
- JVM實用參數(六) 吞吐量收集器
- JVM實用參數(七)CMS收集器
- JVM實用參數(八)GC日志
- Java性能調優原則
- JVM 優化經驗總結
- 面試題整理
- 面試題1
- java日志規約
- Spring安全
- OAtuth2.0簡介
- Spring Session 簡介(一)
- Spring Session 簡介(二)
- Spring Session 簡介(三)
- Spring Security 簡介(一)
- Spring Security 簡介(二)
- Spring Security 簡介(三)
- Spring Security 簡介(四)
- Spring Security 簡介(五)
- Spring Security Oauth2 (一)
- Spring Security Oauth2 (二)
- Spring Security Oauth2 (三)
- SpringBoot
- Shiro
- Shiro和Spring Security對比
- Shiro簡介
- Session、Cookie和Cache
- Web Socket
- Spring WebFlux