1. 程式人生 > >解釋執行和編譯執行的區別、基於棧和基於暫存器的指令集區別

解釋執行和編譯執行的區別、基於棧和基於暫存器的指令集區別

1. 解釋執行和編譯執行的區別

我們在學習java的時候,對class檔案都有個疑惑,虛擬機器是如何執行發方法中的位元組碼指令的呢?其實 虛擬機器的執行引擎在執行java程式碼的時候有解釋執行和編譯執行兩種選擇。通俗說來,解釋執行是通過直譯器執行,編譯執行即通過即時編譯器產生原生代碼執行。
開始前,先了解下大部分的程式程式碼到物理機的目的碼或虛擬機器的指令集之前,要經過下圖步驟, 先看圖:
這裡寫圖片描述
此圖下面一條路徑就是傳統編譯原理中程式程式碼到目的碼的生成過程。而中間的分支就是解釋執行的過程。一般的虛擬機器語言都會基於現代經典編譯原理的思路實現,在執行前先對程式原始碼進行詞法分析,這個階段的任務是從左到右一個字元一個字元地讀入源程式,對構成源程式的字元流進行掃描然後根據構詞規則識別單詞(也稱單詞符號或符號,如識別符號、常數、運算子、定界符等),獲取單詞流。而後進行語法分析

,它的作用是從輸入中分析出其結構並將其轉換為在後續處理過程中更易於訪問的資料結構(一般是樹類的資料結構),並檢測可能存在的語法錯誤。經過詞法分析和語法分析後原始碼被轉換成抽象語法樹(Abstract Syntax Tree,AST)。對於具體的語言實現來說,詞法分析、語法分析和後面的優化器以及目的碼生成器都可選擇獨立的執行引擎,形成一個完整意義的編譯器去實現,比如C/C++;也可以選擇把其中的一部分步驟(如生成抽象語法樹之前)實現為一個半獨立的編譯器,比如Java;又或者把這些步驟和執行引擎全部集中封裝在一個封閉黑匣子中,如大多數JavaScript執行器。

java語言中,javac編譯器完成原始碼的詞法分析、語法分析到抽象語法樹,再便利語法樹生成線性位元組碼指令流。這一部分是在java虛擬機器之外進行的,而直譯器在虛擬機器內部,因此java程式的編譯是半獨立的。

1.1 解釋執行

解釋執行是高階語言翻譯程式的一種,它將源語言編寫的源程式作為輸入,解釋一句就提交給計算機執行一句,並不形成目標程式。例如翻譯領域的“口譯”一樣。
優點:方便快捷,適合小型機計算;不依賴於平臺;
缺點:解釋程式執行緩慢,效率低下,如源程式有迴圈時,計算機資源大量浪費。

1.2 編譯執行

編譯執行把高階語言源程式作為輸入,進行翻譯轉換產出機器語言的目標程式,讓計算機直接執行目標程式的到計算結果。
優點:編譯完成後可多次使用,生成的可執行檔案效率高,佔用資源少,適用於複雜的程式。
缺點:相容性差,編譯過程需要很多時間開銷。

現在很多語言使用二者結合方式,如Java、Python等。

2. 基於棧和基於暫存器的指令集區別

上面說了java是解釋執行和編譯執行相結合的,那麼對於java編譯器輸出的位元組流,java是如何執行的呢?其基本是一種基於棧的指令集架構,指令流中的指令大部分是零地址指令,它們依賴運算元棧進行工作。而基於暫存器的指令集(主流pc直接支援的指令集架構)依賴於暫存器進行工作。
舉個例子:當我們計算1+1的時候,
基於棧的指令集會是這樣:

iconst_1
iconst_1 //兩條iconst_1指令連續把兩個常量1壓入棧
iadd     //iadd指令把棧頂的兩個值出棧、相加後把結果放回棧頂。
istore_0 //把棧頂值存入區域性變量表第0個slot中

基於暫存器的指令是這樣:

mov eax,1   //將eax暫存器址設為1
add eax,1   //將eax暫存器與1相加結果依舊存入eax暫存器

我們不難得出:
1.基於棧的指令集
優點:可移植(暫存器由硬體提供,程式依賴硬體暫存器會收到硬體約束),基於棧的指令集架構,使用者不會直接使用這些暫存器,由虛擬機器實現決定把一些訪問頻繁的資料放到暫存器中獲得儘量更好的效能;還有優點是程式碼相對緊湊(位元組碼中每個位元組對應一條指令)、編譯器實現簡單(無需考慮空間分配)等;
缺點:執行速度慢,效率較低。因為操作本身伴隨著大量的入棧出棧,導致完成相同功能所需的指令數量增加;更重要的是棧實現在記憶體中,頻繁的棧訪問意味著頻繁的記憶體訪問,這大大降低了效率。

2.基於暫存器的指令集
優點:效率相對較高
缺點:平臺依賴,可移植性差。編譯實現複雜。(相對於基於棧來說)