C/C++藏否、Java由源碼到機(jī)器碼的過程(編譯原理)

? ? 軟件開發(fā)的環(huán)境需要什么?一個(gè)IDE充包,一個(gè)OS副签,一個(gè)硬件設(shè)備,沒錯(cuò)基矮,這個(gè)實(shí)質(zhì)是軟件進(jìn)展的三個(gè)層集淆储。在很久很久以前(幾十年),軟件就是直接開發(fā)在硬件設(shè)備上的家浇,用紙帶有無孔標(biāo)識二進(jìn)制位本砰,此時(shí)的開發(fā)語言是機(jī)器碼,軟件直接對接硬件設(shè)備钢悲;后來很不方便点额,尤其不方便復(fù)用,然后莺琳,有了匯編还棱,有了簡單的編譯環(huán)境,然后逐漸發(fā)展成為OS內(nèi)核惭等;時(shí)代會進(jìn)步珍手,軟件要處理越來越多復(fù)雜的場景,然后有了高級語言:C等,為了更加高效友好的開發(fā)琳要,有了最初期的IDE料扰,2000年左右的程序員,應(yīng)該用記得有一個(gè)Turbo C焙蹭,這個(gè)也是我的入門IDE,這個(gè)至少要比記事本寫代碼方便了一些嫂伞。軟件的規(guī)模越來越大孔厉,行業(yè)分工越來越細(xì),開發(fā)的效率也越發(fā)的重要帖努,以Android為例撰豺,從Eclipse到google官方所推的Android Studio,IDE的功能越來越強(qiáng)大拼余,這個(gè)解放了程序員污桦,但也控制了程序員,有誰還會知道匙监,寫在這些IDE中的代碼行凡橱,為什么可以執(zhí)行在手機(jī)上?中間有什么過程亭姥,是什么模塊在控制這些過程稼钩?是完全由IDE實(shí)現(xiàn)的嗎?我相信能答出這個(gè)問題的人是少數(shù)达罗。古人說過坝撑,要知其然,還要知其所以然粮揉,只會使用IDE去寫固定的功能模塊巡李,只是一個(gè)普通碼農(nóng),要想用好一個(gè)工具(包括IDE及語言)扶认,還要了解其實(shí)質(zhì)侨拦,要明白,我們寫好的代碼蝠引,是怎么運(yùn)行到硬件環(huán)境上的阳谍。這個(gè)話題很大,包括編譯原理螃概、OS結(jié)構(gòu)矫夯、硬件驅(qū)動(dòng)、各種語言等吊洼。大不是不去了解的理由训貌,技術(shù)的提交需要反復(fù)的打磨,好,先來揭個(gè)蓋子递沪,看一下C/C++及Java由代碼到機(jī)器碼的過程豺鼻,有了機(jī)器碼之后,再后面的運(yùn)行細(xì)節(jié)款慨,離軟件開發(fā)離得較遠(yuǎn)儒飒,和開發(fā)優(yōu)質(zhì)軟件平臺(除OS外)關(guān)系也不太大。

? ? 由源碼到機(jī)器碼檩奠,C/C++與Java的實(shí)現(xiàn)并不相同桩了,為什么要放在一起呢,三個(gè)原因吧:(一)從語言代來講埠戳,C為二代面向過程語言井誉、C++為三代面向?qū)ο笳Z言,Java為參考C++所設(shè)計(jì)的三代面向?qū)ο笳Z言整胃,其本身是有傳承的颗圣,語言會傳承,編譯運(yùn)行環(huán)境同樣是傳承的屁使,對比著看在岂,可以看出優(yōu)化方向;(二)我目前主要是在做Android開發(fā)的相關(guān)方面屋灌,這個(gè)是與自身最切身相關(guān)的語言洁段,Android的內(nèi)核是C/C++環(huán)境、應(yīng)用層和framework層是Java環(huán)境共郭,對這兩門語言有迫切的項(xiàng)目需求祠丝。(三)個(gè)人認(rèn)為,C/C++除嘹、Java作為靜態(tài)語言写半,其應(yīng)用范圍、語言特性尉咕,編譯運(yùn)行原理非常有代表性叠蝇,尤其是Java在做跨平臺,之后JVM上可以運(yùn)行其他的動(dòng)態(tài)語言年缎,可以說Java的編譯運(yùn)行可以代表一部分希望跨平臺的動(dòng)態(tài)語言悔捶,比如Kotlin。

? ? 先來看一下C/C++的源碼到機(jī)器語言過程發(fā)生了什么单芜,分為四個(gè)大步驟:預(yù)編譯蜕该、編譯、匯編洲鸠、鏈接堂淡,在C/C++中統(tǒng)稱為編譯馋缅。

? ? (一)預(yù)編譯所處理的過程包括:

? ? ? ? a.展開宏定義#define

? ? ? ? b.處理?xiàng)l件預(yù)編譯指令#if等

? ? ? ? c.處理#include

? ? ? ? d.刪除注釋

? ? ? ? e.為Debug及日志填加行號

? ? ? ? f.保留#pragma

? ? (二)編譯所處理的過程包括:

? ? ? ? a.詞法分析:使用掃描器將源碼分隔為一系列的記號(Token),即源碼中的不可分隔項(xiàng)绢淀,較為容易理解萤悴,比如下面的:

? ? ? ? int index = (2?+ 8) * c? 會被折分為 :int index = ( 2 + 8 ) * c? 10個(gè)token,左右半括號各為一個(gè)

? ? ? ? b.語法分析

? ? ? ? 將a中分出來的Token皆的,映射為語法樹

? ? ? ? c.語義分析

? ? ? ? 在b中語法樹的基礎(chǔ)上覆履,分析是否有錯(cuò)誤語義,編譯器所能分析的語義為靜態(tài)語義费薄,包括:聲明是否正確内狗、類型是否匹配、類型的轉(zhuǎn)換是否符合要求

? ? ? ? d.經(jīng)過前面三個(gè)過程后义锥,將源代碼轉(zhuǎn)換為中間語言,可以理解為將c中通過的語法樹通過一定的規(guī)則拍平岩灭,變?yōu)轭惣儆谀繕?biāo)代碼的結(jié)構(gòu)拌倍,為什么要引入中間語言呢,目標(biāo)語言很多時(shí)候是硬件相關(guān)的噪径,而中間語言與硬件無關(guān)柱恤。

? ? ? ? e.生成目標(biāo)代碼并進(jìn)行相應(yīng)優(yōu)化

? ? ? ? 目標(biāo)代碼的文件組織格式為.o文件,其內(nèi)部的格式與具體設(shè)備有很大關(guān)系找爱,比如在Android中梗顺,對arm7和x86CPU要編譯出不同的so文件,此處同理车摄,不同的硬件環(huán)境生成不同的目標(biāo)代碼寺谤。目標(biāo)代碼的優(yōu)化也是針對不同情況有不同處理,在此不再展開吮播,感興趣的同學(xué)可以參考編譯原理相關(guān)書籍变屁。

? ? (三)匯編:匯編的目的是把匯編語言轉(zhuǎn)為機(jī)器語言,基本是一條轉(zhuǎn)一條意狠,沒啥特殊的

? ? (四)鏈接:鏈接是要解決目標(biāo)文件之間的互相依賴關(guān)系粟关,當(dāng)a文件中的aa方法中調(diào)用了b文件的bb方法時(shí),在匯編完成后环戈,a文件的bb方法并沒有準(zhǔn)確的內(nèi)存地址闷板,鏈接后會轉(zhuǎn)換為虛擬地址,虛擬地址可以依據(jù)一定的規(guī)則轉(zhuǎn)換為實(shí)際地址院塞,即可以運(yùn)行時(shí)找到該方法遮晚。鏈接過程包括:地址和空間分配、符號決議和重定位迫悠,之后的文檔中可以再總結(jié)下鹏漆。

? ? Java語言從源代碼到機(jī)器碼的過程要比C/C++復(fù)雜,Java追求的是一次編譯,多次運(yùn)行的跨平臺特性艺玲,因而在分層上更為徹底括蝠。可以分為編譯期和運(yùn)行期兩個(gè)周期饭聚,編譯期的輸入為源代碼.java文件忌警、輸出為字節(jié)碼.class文件、運(yùn)行期輸入為字節(jié)碼.class文件秒梳,輸出為機(jī)器碼法绵。為何這么做可以跨平臺呢,JVM定義了嚴(yán)格的.class文件的格式酪碘,Java文件需要嚴(yán)格按照定義編譯為.class文件朋譬,然后可以拿到各個(gè)平臺各個(gè)版本的虛擬機(jī)上運(yùn)行。如果其他的語言編譯完畢后也遵循.class文件格式兴垦,也可以在JVM上和Java一樣運(yùn)行徙赢。

? ? 先來看Java的編譯期,有以下幾個(gè)過程:

? ? (一)生成語法樹及符號表的過程:

? ? ? ? a.首先進(jìn)行詞法分析探越,將源碼的字符流分解為token的集合狡赐,token的含義可以參考上面所提到的,即不可折分的個(gè)體

? ? ? ? b.語法分析钦幔,根據(jù)token集合構(gòu)建抽象語法樹

? ? ? ? c.生成符號表:符號表是一個(gè)類key-value結(jié)構(gòu)的集合枕屉,記錄符號的類型、結(jié)構(gòu)鲤氢、定義搀擂,支持增加與刪除

? ? (二)處理Java語言中的注解,修正(一)中生成的語法樹

? ? (三)語義分析卷玉,與C/C++的語義分析類似哥倔,進(jìn)行一些語義正確性檢測,具體包括:

? ? ? ? a.標(biāo)注檢查:類型聲明及賦值是否合適

? ? ? ? b.常量折疊:將 1 + 2 直接用3替代

? ? ? ? c.上下文的語法檢測揍庄,如變量使用前是否賦值等

? ? ? ? d.解語法糖咆蒿,為了提升開發(fā)效率,Java提供了許多的語法糖蚂子,比如:泛型沃测、變長參數(shù)、自動(dòng)裝箱等食茎,在此過程中蒂破,會將這些語法糖轉(zhuǎn)為JVM所規(guī)定的格式。具體可以查看Java虛擬機(jī)中相關(guān)語法編譯期的處理

? ? (四)生成字節(jié)碼别渔,生成字節(jié)碼階段主要是兩個(gè)事情:

? ? ? ? a.按照抽象語法樹及符號表生成相應(yīng)的字節(jié)碼

? ? ? ? b.針對Java語言的特點(diǎn)附迷,進(jìn)行些必要的填充惧互,比如:字符串的+轉(zhuǎn)為StringBuilder等

? ? 經(jīng)過上述四個(gè)過程,Java中的編譯期即進(jìn)行完畢了喇伯,可以獲取到.class文件喊儡,如果對.class文件格式感興趣,可以看我之前的文章:https://blog.csdn.net/kcstrong/article/details/79460262

? ? 繼續(xù)分析下Java的運(yùn)行期稻据,先看下運(yùn)行期有什么特點(diǎn)艾猜。首先,運(yùn)行期離Java語言的使用者捻悯,離得較遠(yuǎn)匆赃,運(yùn)行期處理的是字節(jié)碼到機(jī)器碼之間的轉(zhuǎn)換,Java語言的使用者不需要了解這些細(xì)節(jié)今缚,也可以進(jìn)行高效的開發(fā)算柳。理解這些細(xì)節(jié),以我當(dāng)前的體驗(yàn)姓言,對于開發(fā)者來講埠居,主要是增長知識面,對開發(fā)的影響也不大事期。那運(yùn)行期和什么樣的開發(fā)者關(guān)系較大呢,沒錯(cuò)纸颜,就是虛擬機(jī)開發(fā)人員或者需要優(yōu)化虛擬機(jī)的人員兽泣,比如,服務(wù)器的運(yùn)維人員胁孙。

? ? Java運(yùn)行期的工作并非是固定的唠倦,最基本的,也是最簡單的涮较,當(dāng)然稠鼻,也可以理解為保底的,是使用解釋器將字節(jié)碼轉(zhuǎn)換為機(jī)器碼狂票,該原理相當(dāng)?shù)那逦鞔_候齿,有以下步驟:

? ? a.按一定的規(guī)則尋找相關(guān)的類,首先闺属,根據(jù)環(huán)境變量找到j(luò)ava類庫的位置慌盯,然后根據(jù)雙親委托模式找到準(zhǔn)確的類位置

? ? b.然后就很簡單了,JVM字節(jié)碼可以直接逐條解釋掂器,只是JVM是基本于棧的指令集亚皂,條數(shù)較多,解釋較為耗時(shí)国瓮。

? ? 另一種Java運(yùn)行期的處理為JIT灭必,是一種Java動(dòng)態(tài)編譯方法狞谱,分為兩種:Client Compiler和Server Compiler

? ??Client Compiler較為簡單快速,其過程用下面一幅圖來說明:


? ?Server Compiler是一個(gè)經(jīng)過充分優(yōu)化的高級編譯器禁漓,包括但不限于:無用代碼擦除跟衅、基本塊重排序等,其技術(shù)極為復(fù)雜璃饱,感興趣的同學(xué)可以查閱專門的資料研究与斤。選用上述那種Compiler進(jìn)行處理,要視環(huán)境的需要而定荚恶。

? ? JIT并非完全取代解釋器撩穿,只是在需要優(yōu)化的高頻方法或高頻模塊(比如多次for循環(huán))才會介入,其他時(shí)候仍采用的是解釋器的處理方式谒撼。

? ? ?針對Java的源碼到機(jī)器碼的處理食寡,上面提到了兩種編譯運(yùn)行方式分別為:編譯為字節(jié)碼+解釋器、編譯為字節(jié)碼+JIT+解析器廓潜。目前還是另一種方式抵皱,為AOT,一種靜態(tài)編譯方式辩蛋,在編譯期呻畸,即將源碼編譯為機(jī)器碼,其好處也是顯然的悼院,運(yùn)行器無JVM處理時(shí)延伤为,效率最高,但缺點(diǎn)也很明顯:(1)犧牲了Java的跨平臺特性据途,機(jī)器碼一定是平臺相關(guān)的(2)編譯算法復(fù)雜度相當(dāng)高绞愚,JIT在運(yùn)行期,通過運(yùn)行時(shí)數(shù)據(jù)收集颖医,制定是否編譯機(jī)器碼位衩,但AOT在編譯期就要收集到這些。

? ??好熔萧,總結(jié)一下糖驴,總共提到的Java的源碼到機(jī)器碼的處理為三種:

? ? ? ? a.編譯為字節(jié)碼+解釋器

? ? ? ? b.編譯為字節(jié)碼+JIT+解析器

? ? ? ? c.AOT直接編譯為機(jī)器碼

? ? Java目前應(yīng)用范圍要大于C/C++,采用那種方式佛致,要看那些場景更為合適遂赠,比如,Android采用的變異后的b方式(編譯后的輸出為dex文件晌杰,運(yùn)行前要將dex文件轉(zhuǎn)化為oat格式跷睦,運(yùn)行時(shí)要處理的格式為oat格式,運(yùn)行時(shí)的指令集為基于寄存器的)

? ? 從上面對C/C++及Java編譯運(yùn)行的分析肋演,可以看出抑诸,編譯的基本原理及流程是相近的烂琴,然后加入了后期的優(yōu)化,尤其是Java蜕乡,為改善編譯及運(yùn)行效率(JIT奸绷、AOT、字節(jié)碼等)层玲,做了大量的工作号醉,至Android虛擬機(jī)(當(dāng)前文中沒細(xì)說),又根據(jù)平臺特點(diǎn)辛块,在Java的基礎(chǔ)上做了大量的改進(jìn)畔派。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市润绵,隨后出現(xiàn)的幾起案子线椰,更是在濱河造成了極大的恐慌,老刑警劉巖尘盼,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件憨愉,死亡現(xiàn)場離奇詭異,居然都是意外死亡卿捎,警方通過查閱死者的電腦和手機(jī)配紫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來午阵,“玉大人躺孝,你說我怎么就攤上這事√俗” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵伪很,是天一觀的道長戚啥。 經(jīng)常有香客問我,道長锉试,這世上最難降的妖魔是什么猫十? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮呆盖,結(jié)果婚禮上拖云,老公的妹妹穿的比我還像新娘。我一直安慰自己应又,他們只是感情好宙项,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著株扛,像睡著了一般尤筐。 火紅的嫁衣襯著肌膚如雪汇荐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天盆繁,我揣著相機(jī)與錄音掀淘,去河邊找鬼。 笑死油昂,一個(gè)胖子當(dāng)著我的面吹牛革娄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播冕碟,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼拦惋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鸣哀?” 一聲冷哼從身側(cè)響起架忌,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎我衬,沒想到半個(gè)月后叹放,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡挠羔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年井仰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片破加。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡俱恶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出范舀,到底是詐尸還是另有隱情合是,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布锭环,位于F島的核電站聪全,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏辅辩。R本人自食惡果不足惜难礼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望玫锋。 院中可真熱鬧蛾茉,春花似錦、人聲如沸撩鹿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽节沦。三九已至吧寺,卻和暖如春窜管,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背稚机。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工幕帆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赖条。 一個(gè)月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓失乾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親纬乍。 傳聞我的和親對象是個(gè)殘疾皇子碱茁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容