词法分析器java_Java代码到底是如何编译成机器指令的。
作者:Hollis
在《Java代碼的編譯與反編譯》中,有過(guò)關(guān)于Java語(yǔ)言的編譯和反編譯的介紹。我們可以通過(guò)javac命令將Java程序的源代碼編譯成Java字節(jié)碼,即我們常說(shuō)的class文件。這是我們通常意義上理解的編譯。
但是,字節(jié)碼并不是機(jī)器語(yǔ)言,要想讓機(jī)器能夠執(zhí)行,還需要把字節(jié)碼翻譯成機(jī)器指令。這個(gè)過(guò)程是Java虛擬機(jī)做的,這個(gè)過(guò)程也叫編譯。是更深層次的編譯。
在編譯原理中,把源代碼翻譯成機(jī)器指令,一般要經(jīng)過(guò)以下幾個(gè)重要步驟:
根據(jù)完成任務(wù)不同,可以將編譯器的組成部分劃分為前端(Front End)與后端(Back End)。
前端編譯主要指與源語(yǔ)言有關(guān)但與目標(biāo)機(jī)無(wú)關(guān)的部分,包括詞法分析、語(yǔ)法分析、語(yǔ)義分析與中間代碼生成。后端編譯主要指與目標(biāo)機(jī)有關(guān)的部分,包括代碼優(yōu)化和目標(biāo)代碼生成等。
我們可以把將.java文件編譯成.class的編譯過(guò)程稱(chēng)之為前端編譯。把將.class文件翻譯成機(jī)器指令的編譯過(guò)程稱(chēng)之為后端編譯。
Java中的前端編譯
前端編譯主要指與源語(yǔ)言有關(guān)但與目標(biāo)機(jī)無(wú)關(guān)的部分,包括詞法分析、語(yǔ)法分析、語(yǔ)義分析與中間代碼生成。
我們所熟知的javac的編譯就是前端編譯。除了這種以外,我們使用的很多IDE,如eclipse,idea等,都內(nèi)置了前端編譯器。主要功能就是把.java代碼轉(zhuǎn)換成.class代碼。
詞法分析
詞法分析階段是編譯過(guò)程的第一個(gè)階段。這個(gè)階段的任務(wù)是從左到右一個(gè)字符一個(gè)字符地讀入源程序,將字符序列轉(zhuǎn)換為標(biāo)記(token)序列的過(guò)程。這里的標(biāo)記是一個(gè)字符串,是構(gòu)成源代碼的最小單位。在這個(gè)過(guò)程中,詞法分析器還會(huì)對(duì)標(biāo)記進(jìn)行分類(lèi)。
詞法分析器通常不會(huì)關(guān)心標(biāo)記之間的關(guān)系(屬于語(yǔ)法分析的范疇),舉例來(lái)說(shuō):詞法分析器能夠?qū)⒗ㄌ?hào)識(shí)別為標(biāo)記,但并不保證括號(hào)是否匹配。
語(yǔ)法分析
語(yǔ)法分析的任務(wù)是在詞法分析的基礎(chǔ)上將單詞序列組合成各類(lèi)語(yǔ)法短語(yǔ),如“程序”,“語(yǔ)句”,“表達(dá)式”等等.語(yǔ)法分析程序判斷源程序在結(jié)構(gòu)上是否正確.源程序的結(jié)構(gòu)由上下文無(wú)關(guān)文法描述。
語(yǔ)義分析
語(yǔ)義分析是編譯過(guò)程的一個(gè)邏輯階段, 語(yǔ)義分析的任務(wù)是對(duì)結(jié)構(gòu)上正確的源程序進(jìn)行上下文有關(guān)性質(zhì)的審查,進(jìn)行類(lèi)型審查。語(yǔ)義分析是審查源程序有無(wú)語(yǔ)義錯(cuò)誤,為代碼生成階段收集類(lèi)型信息。
語(yǔ)義分析的一個(gè)重要部分就是類(lèi)型檢查。比如很多語(yǔ)言要求數(shù)組下標(biāo)必須為整數(shù),如果使用浮點(diǎn)數(shù)作為下標(biāo),編譯器就必須報(bào)錯(cuò)。再比如,很多語(yǔ)言允許某些類(lèi)型轉(zhuǎn)換,稱(chēng)為自動(dòng)類(lèi)型轉(zhuǎn)換。
中間代碼生成
在源程序的語(yǔ)法分析和語(yǔ)義分析完成之后,很多編譯器生成一個(gè)明確的低級(jí)的或類(lèi)機(jī)器語(yǔ)言的中間表示。該中間表示有兩個(gè)重要的性質(zhì): 1.易于生成; 2.能夠輕松地翻譯為目標(biāo)機(jī)器上的語(yǔ)言。
在Java中,javac執(zhí)行的結(jié)果就是得到一個(gè)字節(jié)碼,而這個(gè)字節(jié)碼其實(shí)就是一種中間代碼。
PS:著名的解語(yǔ)法糖操作,也是在javac中完成的。
Java中的后端編譯
首先,我們大家都知道,通常通過(guò) javac 將程序源代碼編譯,轉(zhuǎn)換成 java 字節(jié)碼,JVM 通過(guò)解釋字節(jié)碼將其翻譯成對(duì)應(yīng)的機(jī)器指令,逐條讀入,逐條解釋翻譯。很顯然,經(jīng)過(guò)解釋執(zhí)行,其執(zhí)行速度必然會(huì)比可執(zhí)行的二進(jìn)制字節(jié)碼程序慢很多。這就是傳統(tǒng)的JVM的解釋器(Interpreter)的功能。為了解決這種效率問(wèn)題,引入了 JIT 技術(shù)。
JAVA程序還是通過(guò)解釋器進(jìn)行解釋執(zhí)行,當(dāng)JVM發(fā)現(xiàn)某個(gè)方法或代碼塊運(yùn)行特別頻繁的時(shí)候,就會(huì)認(rèn)為這是“熱點(diǎn)代碼”(Hot Spot Code)。然后JIT會(huì)把部分“熱點(diǎn)代碼”翻譯成本地機(jī)器相關(guān)的機(jī)器碼,并進(jìn)行優(yōu)化,然后再把翻譯后的機(jī)器碼緩存起來(lái),以備下次使用。
HotSpot虛擬機(jī)中內(nèi)置了兩個(gè)JIT編譯器:Client Complier和Server Complier,分別用在客戶(hù)端和服務(wù)端,目前主流的HotSpot虛擬機(jī)中默認(rèn)是采用解釋器與其中一個(gè)編譯器直接配合的方式工作。
當(dāng) JVM 執(zhí)行代碼時(shí),它并不立即開(kāi)始編譯代碼。首先,如果這段代碼本身在將來(lái)只會(huì)被執(zhí)行一次,那么從本質(zhì)上看,編譯就是在浪費(fèi)精力。因?yàn)閷⒋a翻譯成 java 字節(jié)碼相對(duì)于編譯這段代碼并執(zhí)行代碼來(lái)說(shuō),要快很多。第二個(gè)原因是最優(yōu)化,當(dāng) JVM 執(zhí)行某一方法或遍歷循環(huán)的次數(shù)越多,就會(huì)更加了解代碼結(jié)構(gòu),那么 JVM 在編譯代碼的時(shí)候就做出相應(yīng)的優(yōu)化。
在機(jī)器上,執(zhí)行java -version命令就可以看到自己安裝的JDK中JIT是哪種模式:
上圖是我的機(jī)器上安裝的jdk1.8,可以看到,他是Server Compile,但是,需要說(shuō)明的是,無(wú)論是Client Complier還是Server Complier,解釋器與編譯器的搭配使用方式都是混合模式,即上圖中的mixed mode。
熱點(diǎn)檢測(cè)
上面我們說(shuō)過(guò),要想觸發(fā)JIT,首先需要識(shí)別出熱點(diǎn)代碼。目前主要的熱點(diǎn)代碼識(shí)別方式是熱點(diǎn)探測(cè)(Hot Spot Detection),有以下兩種:
1、基于采樣的方式探測(cè)(Sample Based Hot Spot Detection) :周期性檢測(cè)各個(gè)線(xiàn)程的棧頂,發(fā)現(xiàn)某個(gè)方法經(jīng)常出險(xiǎn)在棧頂,就認(rèn)為是熱點(diǎn)方法。好處就是簡(jiǎn)單,缺點(diǎn)就是無(wú)法精確確認(rèn)一個(gè)方法的熱度。容易受線(xiàn)程阻塞或別的原因干擾熱點(diǎn)探測(cè)。
2、基于計(jì)數(shù)器的熱點(diǎn)探測(cè)(Counter Based Hot Spot Detection)。采用這種方法的虛擬機(jī)會(huì)為每個(gè)方法,甚至是代碼塊建立計(jì)數(shù)器,統(tǒng)計(jì)方法的執(zhí)行次數(shù),某個(gè)方法超過(guò)閥值就認(rèn)為是熱點(diǎn)方法,觸發(fā)JIT編譯。
在HotSpot虛擬機(jī)中使用的是第二種——基于計(jì)數(shù)器的熱點(diǎn)探測(cè)方法,因此它為每個(gè)方法準(zhǔn)備了兩個(gè)計(jì)數(shù)器:方法調(diào)用計(jì)數(shù)器和回邊計(jì)數(shù)器。
方法計(jì)數(shù)器。顧名思義,就是記錄一個(gè)方法被調(diào)用次數(shù)的計(jì)數(shù)器。
回邊計(jì)數(shù)器。是記錄方法中的for或者while的運(yùn)行次數(shù)的計(jì)數(shù)器。
編譯優(yōu)化
前面提到過(guò),JIT除了具有緩存的功能外,還會(huì)對(duì)代碼做各種優(yōu)化。說(shuō)到這里,不得不佩服HotSpot的開(kāi)發(fā)者,他們?cè)贘IT中對(duì)于代碼優(yōu)化真的算是面面俱到了。
這里簡(jiǎn)答提及幾個(gè)我覺(jué)得比較重要的優(yōu)化技術(shù),并不準(zhǔn)備直接展開(kāi),讀者感興趣的話(huà),我后面再寫(xiě)文章單獨(dú)介紹。
逃逸分析、 鎖消除、 鎖膨脹、 方法內(nèi)聯(lián)、 空值檢查消除、 類(lèi)型檢測(cè)消除、 公共子表達(dá)式消除。
總結(jié)
以上是生活随笔為你收集整理的词法分析器java_Java代码到底是如何编译成机器指令的。的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: mysql-plus多数据库_IDEA项
- 下一篇: java hashtable put_J