編譯型與解釋型語言 虛擬機器 && JVM && JIT AOT &GCC Clang LLVM 等簡介
概述
對編譯型與解釋型語言、compiler assembler interpreter、jvm等內容做簡單的瞭解。可能有錯誤之處。
想要進一步瞭解某個技術的話,需要繼續深入研究。
編譯型語言&compiler assembler
使用專門的編譯器,針對特定的平臺,將高階語言原始碼一次性的編譯成可被該平臺硬體執行的機器碼。平臺間區別主要是CPU(arm、x86、mips等)架構和檔案格式(ELF\PE)
在編譯型語言寫的程式執行之前,需要一個專門的編譯過程,把原始碼編譯成機器語言的檔案。如PE格式的可執行檔案exe,以後要再執行時,直接使用編譯結果即可,如直接執行exe檔案。
優點:只需編譯一次,以後執行時不需要編譯。執行效率高。
缺點:程式碼在編譯過程中就已經被翻譯成了目標 CPU 指令、檔案格式,所以,如果程式需要在另外一種 CPU 、檔案格式不同的作業系統上面執行,這個程式碼就必須重新編譯。
典型的編譯型語言:.C、C++、Pascal、Object-C,Swift
要注意,具體語言和具體的編譯器,具體分析。
GCC
例如使用gcc編譯C語言。 原始檔(.c)->預處理(.i)->編譯(compile)得到彙編指令檔案(.s)->彙編(assemble)得到機器語言的目標檔案(.o .obj)->連結得到可執行檔案
這幾個步驟分別有 preprocessor、compiler、assembler、linker完成
對應的disassembler是機器語言到組合語言,而Decompile是彙編到高階語言
解釋型語言與直譯器
解釋型語言執行時,由直譯器 逐條 ,直接翻譯為 CPU指令(機器碼),執行。邊解釋邊執行,且必須在執行時解釋。好處就是方便,但缺點是效率低。
典型的解釋型語言有:Python/JavaScript / Perl /Shell
但是需要注意的是,不同的解釋型語言也有實現上的不同。
Javascript
比如javascript,不同瀏覽器有不同的JS引擎。 ,也就有不同的執行方式。
傳統的引擎,詞法分析和語法分析得到語法樹,然後有一個“預編譯”過程,然後按照逐條解釋執行。
部分引擎先轉換為位元組碼,然後解釋。
然而google的V8,為了提高效率,直接編譯成原生機器碼。 https://zhuanlan.zhihu.com/p/295179301
對於不同的引擎,要具體分析
Python
比如python,會預先編譯為位元組碼,然後python虛擬機器會逐條的解釋位元組碼。和下面要提到的Java有些類似(從這個角度看,python似乎不是典型的解釋型語言,和java更類似,除非把python虛擬機器看作python直譯器) https://www.cnblogs.com/webber1992/p/6597166.html
此外,解析器是parser,而直譯器是interpreter。前者是編譯器/直譯器的重要組成部分,也可以用在IDE之類的地方;其主要作用是進行語法分析,提取出句子的結構。廣義來說輸入一般是程式的原始碼,輸出一般是語法樹(syntax tree,也叫parse tree等)或抽象語法樹(abstract syntax tree,AST)。 https://www.iteye.com/blog/rednaxelafx-492667
總結1
解釋和編譯以及虛擬機器等等技術,更多的是概念上的區別。很多語言並不是嚴格的只有解釋、完全只有靜態編譯。
隨著技術的發展,各種技術互相結合以提高語言編譯執行的效率。
虛擬機器
虛擬機器分為兩大類:系統虛擬機器和程序虛擬機器。這兩種虛擬機器都提供一種對“真實的”計算硬體的不同級別的抽象,不過它們的作用域不同。系統虛擬機器是一個提供物理硬體的替代品的軟體,而程序虛擬機器則被設計用來以一種“系統獨立”的方式執行程式。
在編譯和程式執行的角度來看,當然是指程序虛擬機器,接下來提到的的VM都是程序虛擬機器。
程序虛擬機器(的作用域和直譯器的比較類似,因為也是先將程式編譯成一箇中間形態,然後虛擬機器再執行這個中間形態。
虛擬機器和直譯器的主要區別在於,虛擬機器創造了一個虛擬的 CPU,以及一套虛擬的指令集。有了這層抽象,我們就可以編寫前端工具來把不同語言的程式編譯成虛擬機器可以接受的程式。最流行也最知名的虛擬機器就是 Java 虛擬機器(JVM)。https://zhuanlan.zhihu.com/p/70949843
JAVA
Java和其他的語言不太一樣,不是完全的解釋型也不是完全的編譯型。
前端編譯
把Java原始碼檔案(.java)編譯成Class檔案(.class)的過程
後端編譯/即時(JIT)編譯
通過Java虛擬機器(JVM)內建的即時編譯器(Just In Time Compiler,JIT編譯器);在執行時把Class檔案位元組碼編譯成本地機器碼的過程;
靜態提前編譯(Ahead Of Time,AOT編譯)
直接把CLASS位元組碼檔案(.java)編譯成本地機器碼的過程,省掉了JVM的過程。
跨平臺
java針對不同的平臺有不同的JVM,實現了跨平臺。
1.你可以說它是編譯型的:因為所有的Java程式碼都是要編譯的,.java不經過編譯就什麼用都沒有。 (此處考慮的是編譯為class,然後jvm執行,而非AOT)
2.你可以說它是解釋型的:因為java程式碼編譯後不能直接執行,它是解釋執行在JVM上的。
JVM
程式設計師在編寫Java程式時,利用Java編譯器,將Java語言編譯為Java ByteCode;之後,執行過程中需要使用相應平臺的JVM(Java虛擬機器)將ByteCode轉化為相應平臺的機器程式碼,如JVM for Windows、JVM for UNIX。從而實現跨平臺執行
對於JVM的設計有三種
1. 執行時,BYTECODE由JVM逐條解釋執行,即直譯器模式。 java interpreter。
2. 執行時,部分程式碼可能由JIT翻譯為目標機器指令(以method為翻譯單位,還會儲存起來,第二次執行就不用翻譯了)直接執行;
3. RTSJ。繼JAVAC生成class檔案後,之後執行AOT二次編譯,生成靜態的目標平臺程式碼(典型的就是IBM WEBSHPERE REAL TIME)。
有的時候,可能是以上三種方式同時在使用。至少前兩者是結合的。例如下圖就是JIT和Java interpreter結合的示例
Java的JIT&&AOT
這部分只是簡單的看了看,可能有理解錯誤。若有需要,應該進一步查詢相關資料。
AOT:
直接把CLASS位元組碼檔案(.java)編譯成本地機器碼的過程,省掉了JVM的過程。
完全的JIT:
所有程式碼都提前編譯。然而顯然代價過高。
熱點型的JIT:
當JVM發現某個方法或程式碼塊執行特別頻繁的時候,就會認為這是“熱點程式碼”(Hot Spot Code)。然後JIT會把部分“熱點程式碼”編譯成本地機器相關的機器碼,並進行優化,然後再把編譯後的機器碼快取起來,以備下次使用。 從而節省時間。 https://www.zhihu.com/question/37389356/answer/73820511
需要注意的是,JIT編譯器將語言 X 轉化為機器程式碼時,需要直譯器的參與。可以認為,沒有直譯器,亦不存在JIT編譯器。
GCC gcc g++
GCC:GNU Compiler Collection(GUN 編譯器集合),它可以編譯C、C++、JAVA、Fortran、Pascal、Object-C等語言。
gcc是GCC中的GUN C Compiler(C 編譯器)
g++是GCC中的GUN C++ Compiler(C++編譯器)
就本質而言,gcc和g++並不是編譯器,也不是編譯器的集合,它們只是一種驅動器,根據引數中要編譯的檔案的型別,呼叫對應的GUN編譯器而已
GCC是許多現代類 Unix 作業系統預設的編譯器,包括 Mac OSX 系統,但後來 Mac OSX 改為用 Clang 編譯器了。
PS:
GNU: https://www.zhihu.com/question/319783573
glibc、glib、libc
Clang&LLVM
Clang
Clang 是一個 C 、 C++ 、 Objective-C 和 Objective-C++ 程式語言的 編譯器 前端。 Clang是 LLVM 編譯器工具集的前端,輸出程式碼對應的抽象語法樹(AST),再編譯成LLVM Bitcode,由後端使用 LLVM 編譯成平臺相關的機器程式碼。LLVM
LLVM是一個編譯器框架。為了提供一個現代的、基於 SSA(靜態單一賦值) 的、可以動態、靜態編譯任何程式語言的編譯方案而開展的研究專案. 關於LLVM,計劃後續繼續做深入的學習。LLVM與JVM
二者根本不是一個範疇的技術,JVM是虛擬機器而LLVM是編譯器框架。
但是可以在某些特定的角度下進行比較,
1.實現一門語言時在選擇程式碼生成器(code generator)的解決方案時,是選擇LLVM、GCC等,還是JVM、.NET等,還是自己手寫
2.二者相結合:Azul Systems公司就在做基於LLVM的JVM JIT編譯器,微軟也有一個組在做基於LLVM的.NET JIT/AOT編譯器
https://www.zhihu.com/question/47819047
參考
解釋型與編譯型:
https://www.jianshu.com/p/54e2aeca013b
https://www.cnblogs.com/zy1987/p/3784753.html
https://www.iteye.com/blog/rednaxelafx-492667
https://zhuanlan.zhihu.com/p/70949843
python:
https://www.cnblogs.com/webber1992/p/6597166.html
v8:
https://zhuanlan.zhihu.com/p/295179301
java&JVM:
https://www.zhihu.com/question/19608553
https://blog.csdn.net/qq_34902684/article/details/85538895
https://www.zhihu.com/question/37389356/answer/73820511
https://www.cnblogs.com/mzywucai/p/11053485.html
GCC gcc:
https://zhuanlan.zhihu.com/p/100050970
https://www.cnblogs.com/liuzhenbo/p/11027197.html
LLVM:
https://www.zhihu.com/question/47819047
https://zhuanlan.zhihu.com/p/140462815
https://www.cnblogs.com/flipped/p/15234552.html