1. 程式人生 > >編譯性語言&解釋性語言

編譯性語言&解釋性語言

計算機是不能理解高階語言,當然也就不能直接執行高階語言了。計算機只能直接理解機器語言,所以任何語言,都必須將其翻譯成機器語言。任何程式語言編寫的程式歸根到底都是由底層機器的機器程式碼(01序列)執行的,無論是編譯型語言還是解釋型語言。而任何高階程式語言程式的原始碼都是一個字元序列,這個字元序列到底層的01序列是通過編譯器或解析器經過多次轉換完成的。

編譯 vs 解釋

翻譯的方式有兩種:一種是編譯,一種是解釋。
兩種方式翻譯的時間不同。

  • 編譯型語言寫的程式在被執行之前,需要一個專門的編譯過程,把程式編譯成為機器語言的檔案,比如exe檔案,以後要執行的話 就不用重新翻譯了,直接使用編譯的結果就行了(exe檔案),因為翻譯只做了一次,執行時不需要翻譯,所以編譯型語言的程式執行效率高,但也不能一概而論,部分解釋型語言的直譯器通過在執行時動態優化程式碼,甚至能夠使解釋型語言的效能超過編譯型語言。

一個完整的編譯系統與 一個用C編寫的程式hello.c的編譯過程
編譯過程

  • 解釋則不同,解釋性語言的程式不需要編譯,省了道工序,解釋性語言在執行程式的時候才翻譯,比如解釋性basic語言,專門有一個直譯器能夠直接執行basic程式,每個語句都是執行的時候才翻譯。這樣解釋性語言每執行一次就要翻譯一次,效率比較低。

編譯型與解釋型兩者各有利弊。
編譯型由於程式執行速度快,同等條件下對系統要求較低,因此像開發作業系統、大型應用程式、資料庫系統等時都採用它,像C/C++、Pascal /Object Pascal(Delphi)等都是編譯語言。

一些網頁尾本、伺服器指令碼及輔助開發介面這樣的對速度要求不高、對不同系統平臺間的相容性有一定要求的程式

則通常使用解釋性語言,如JavaScript、VBScript、Perl、Python、Ruby、MATLAB 等等。

解釋型語言每句程式碼只有在執行時,系統才知道這句程式碼是否有錯(除Java那種先編譯後解釋性語言)。換句話說,由於編譯型語言在執行前進行了編譯,編譯器對所有程式碼都進行了檢查,這樣就不會產生一些低階錯誤,例如使用了不存在的名字,或者使用了錯誤的名字。而JavaScript就可能會出現這些問題。

但隨著硬體的升級和設計思想的變革,編譯型和解釋型語言越來越籠統,主要體現在一些新興的高階語言上,而解釋型語言的自身特點也使得編譯器廠商願意花費更多成本來優化直譯器。

JAVA

JAVA語言是一種編譯型-解釋型語言,同時具備編譯特性和解釋特性(其所謂的編譯過程只是將.java檔案程式設計成平臺無關的位元組碼.class檔案,並不是像C一樣編譯成可執行的機器語言)。 作為編譯型語言,JAVA程式要被統一編譯成位元組碼檔案——檔案字尾是class。此種檔案在java中又稱為類檔案。java類檔案不能再計算機上直接 執行,它需要被java虛擬機器翻譯成本地的機器碼後才能執行,而java虛擬機器的翻譯過程則是解釋性的。java位元組碼檔案首先被載入到計算機記憶體中,然後讀出一條指令,翻譯一條指令,執行一條指令,該過程被稱為java語言的解釋執行,是由java虛擬機器完成的。而在現實中,java開發工具JDK提供了兩個很重要的命令來完成上面的編譯和解釋(翻譯)過程。兩個命令分別是javac.exe和java.exe,前者載入java類檔案,並逐步對位元組碼檔案進行編譯,而另一個命令則對應了java語言的解釋(javac.exe)過程。在次序上,java語言是要先進行編譯的過程,接著解釋執行。

位元組碼的設計並不專門針對任何一種特定的處理器硬體平臺對應的指令程式碼(比如,Intel的Pentium微處理器或IBM的System/390處理器)。位元組碼是可以傳送給任何平臺並且能在那個平臺上執行的獨立於平臺的程式碼。非常類似於機器指令的指令編碼。因而通過Java的虛擬機器就可以很容易的直接將位元組碼轉換成對應於特定 CPU的機器碼,從而得到較高的效能。這種轉換的效率比其他解釋性語言如Basic、Perl等要高得多,甚至在非常低檔的CPU上也能順利執行。不過 Java畢竟是解釋性的語言,它解釋執行的意義在於能夠實現程式一經編譯便可在眾多不同的計算機上執行的跨平臺執行。雖然這比C程式慢了許多,但在大多數應用中都是可以接受的。而且,現在Java也已經有了專門的程式碼生成器,可以很容易使用JIT編譯技術將位元組碼直接轉換成高效能的本機程式碼。值得一提的是,Java執行時系統在提供這個特性的同時仍具有平臺獨立性,因而“高效且跨平臺”對Java來說不再矛盾。

“理解位元組碼以及理解Java編譯器如何生成Java位元組碼與學習彙編知識對於C/C++程式設計師有一樣的意義。”

當前已經有很多種Java虛擬機器產品,包括了自由軟體和商業軟體。 如果在Java虛擬機器之中執行Java位元組碼並不理想,則可以使用一些工具例如GNU Compiler for Java將Java程式碼或Java位元組碼編譯成機器碼並由硬體直接執行。 而有一些處理器可以直接執行Java位元組碼,這種處理器名為Java處理器

C#

C#語言是編譯型語言,但其“編譯”過程比較特殊,具體說明如下:

C#程式在第一次執行的時候,會依賴其.NET Frameworker平 臺,編譯成IL中間碼),然後由JIT compiler翻譯成本地的機器碼執行。從第二次在執行相同的程式,則不需要再執行以上編譯和翻譯過程,而是直接執行第一次翻譯成的機器碼。所以對於 C#來說,通常第一次執行時間會很長,但從第二次開始,程式的執行時間會快很多。

那麼,C#為什麼要進行兩次“編譯”呢?其實,微軟想通過動態編譯(由JIT compiler工具實現)來實現其程式執行的最優化。如果程式碼在執行前進行動態編譯執行,那麼JIT compiler可以很智慧的根據你本地機器的硬體條件來進行優化,比如使用更好的register,機器指令等等,而不是像原來那樣,build一份程式針對所有硬體的機器跑,沒有充分利用各個機器的條件。

指令碼語言

注:指令碼語言一般都有相應的指令碼引擎來解釋執行。 他們一般需要直譯器才能執行。JAVASCRIPT,ASP,PHP,PERL都是指令碼語言。C/C++編譯、連結後,可形成獨立執行的exe檔案。

JIT (JIT compiler,just-in-time compiler,即時編譯器)

JIT編譯器能夠將MSIL編譯成為各種不同的機器程式碼,以適應對應的系統平臺,最終使得程式在目標系統中得到順利地執行。

在Java程式語言和環境中,即時編譯器(JIT compiler,just-in-time compiler)是一個把Java的位元組碼(包括需要被解釋的指令的程式)轉換成可以直接傳送給處理器的指令的程式。

JIT編譯器分為:經濟編譯器和普通編譯器。

JVM (Java Virtual Machine,Java虛擬機器)

JVM是一種用於計算裝置的規範,它是一個虛構出來的計算機,是通過在實際的計算機上模擬模擬各種計算機功能來實現的。

Java語言的一個非常重要的特點就是與平臺的無關性。而使用Java虛擬機器是實現這一特點的關鍵。一般的高階語言如果要在不同的平臺上執行,至少需要編譯成不同的目的碼。而引入Java語言虛擬機器後,Java語言在不同平臺上執行時不需要重新編譯。Java語言使用Java虛擬機器遮蔽了與具體平臺相關的資訊,使得Java語言編譯程式只需生成在Java虛擬機器上執行的目的碼(位元組碼),就可以在多種平臺上不加修改地執行。Java虛擬機器在執行位元組碼時,把位元組碼解釋成具體平臺上的機器指令執行。這就是Java的能夠“一次編譯,到處執行”的原因。

參考連結

問題

現在Java也已經有了專門的程式碼生成器,可以很容易使用JIT編譯技術將位元組碼直接轉換成高效能的本機程式碼。值得一提的是,Java執行時系統在提供這個特性的同時仍具有平臺獨立性,因而“高效且跨平臺”對Java來說不再矛盾。

此處的JIT編譯技術是像JVM一樣,在不同平臺上運用不同的JIT編譯器將.class 翻譯成相應的本機程式碼嗎?下次還需要再翻譯嗎?還是以後直接可以運行了?

補:
Java是一門高階語言。而不同廠商的設計下的體系結構對應一套適應於其硬體的機器指令。為了在跨平臺,發明了JVM。而為了加快執行速率,又提出了自己的中間語法表示,即byte code。

對位元組碼邊讀取邊解釋邊執行自然比不上編譯後的可執行程式。由於採用面向物件設計,我們把資料和方法繫結在了一起,只要資料還在堆上,那麼其方法也就可能用到。即下一條待執行的語句呼叫某個物件的方法的機率存在,為此引入JIT,將常用位元組碼對應的機器碼進行快取。
詳情見如下兩篇端blog:
Javac編譯與JIT編譯
小談JVM及JIT

可以發現,JIT技術的引入使得JVM跑起來更加的臃腫。本質上是以空間換時間。