「這里的虛擬機不是模擬完整硬件的虛擬機,這里主要了解的是JVM與DVM的架構,它們執行的是字節碼。」
虛擬機的設計架構有兩種: 基于求值棧、基于寄存器,如果從更大的范圍可以認為只要實現了功能的都可以認為是虛擬機,通過直接遍歷AST得到結果的也可以算一種虛擬機。
「基于AST」 的虛擬機是通過后序遍歷AST節點,利用調用棧遞歸的對AST求值,它的特點就是實現更簡單,利用更低級語言或者自身來實現。
「基于求值堆棧」 的虛擬機是零地址指令設計的一個很好的實踐,它的操作數是隱藏在棧頂的,利用了棧的先進后出的特點實現了運算的優先級,相對比寄存器方案他的指令數量更多,但是空間占用更低。
「基于虛擬寄存器」 的虛擬機可以是二地址或者三地址設計,操作數存放在虛擬寄存器中,很多指令只需要對寄存器進行讀取,不涉及到速度慢了很多的內存,相對于求值棧的方案,指令數量更少,空間占用更高。
「有圖有真相」
下面我們來看一段非常簡單的Java代碼,直觀的感受一下求值棧與寄存器方案的差異。
class Test {
public static void foo() {
int a = 1;
int b = 2;
int c = (a + b) * 5;
}
}
「求值棧寄存器」
這個程序很簡單,使用javac
將它編譯成字節碼,再利用javap查看指令
javac Test.java
javap -v Test
得到如下指令:
接下來,通過觀察指令執行流程了解JVM基于棧的邏輯:
可以看出,基于求值棧的VM在執行的時候會反復的對棧進行push與pop的操作,這樣一來需要執行的指令條數就多了。
當然,上面的指令是未優化的,實際上在生成指令之前可以將a與b直接優化掉(常數折疊),減少內存占用。
「寄存器虛擬機」
同樣是執行Java代碼, android 的Dalvik VM是采用基于寄存器的架構,通過以下命令:
dx --dex --no-optimize --output Test.dex Test.class
如果不顯示的指定--no-optimize,生成的Test.dex經過優化后,foo函數里面所有的變量與運算都被優化掉了,只剩下一個return-void
指令,從上下文分析可以得出foo內部的a,b,c變量與其參與的運算都可以不需要。不經過優化的指令如下:
指令執行流程如下:編譯期已經確定棧幀的虛擬寄存器的數量,v3 v4是加載數據與運算時使用的寄存器,v0 v1 v2則對面最后三個變量。
數據一量裝入寄存器,在盡可能不使用內存的情況下只使用寄存器速度快得多,因為它不用頻繁與內存打交道了。
任何事物都有兩面性,棧相比寄存器架構它的可移植性更強,棧在任何機器上實現都很容易。在java設計之初就希望它是一個能在所有平臺上通吃的語言,所以JVM基于棧。
而寄存器架構的VM往往會把虛擬寄存器與實際的寄存器映射,如果虛擬寄存器的數量小于等于實際的寄存器,則實現起來相對容易,如果虛擬寄存器數量大于了實際的寄存器數量則相對復雜。
Dalvik只用于android平臺,性能往往是更需要關注的東西,這樣來講android 4.0x開始基于寄存器的DVM就可以理解了,此時的設備內存普遍高而且CPU的寄存器數量也多。
「總結:」 棧與寄存器架構各有優劣,任何的事物在設計之初都有它考慮的重點,它們沒有絕對的優劣,如果你要用AST來實現運算,只要滿足了你的要求,無可厚非。
好比時間與空間在寫的程序里永遠是一個矛盾的存在,人們總是在追求一個極致的平衡點。
如果你覺得文章對你有幫助,可以分享給更多的人或者點在看
。
-
寄存器
+關注
關注
31文章
5336瀏覽量
120230 -
虛擬機
+關注
關注
1文章
914瀏覽量
28160 -
AST
+關注
關注
0文章
7瀏覽量
2327
發布評論請先 登錄
相關推薦
評論