Python的虛擬機(virtual machine)~1
時間:2023-07-01 05:30:02 | 來源:網(wǎng)站運營
時間:2023-07-01 05:30:02 來源:網(wǎng)站運營
Python的虛擬機(virtual machine)~1:
虛擬機(virtual machine)我們經(jīng)常會遇到虛擬機這個概念,但不同的場合其含義卻不相同:
1) 一種是用軟件模擬整個機器的硬件系統(tǒng),有了這個軟件你相當(dāng)于多了一臺裸機,然后你就可以在里面裝操作系統(tǒng)。比如,你的電腦已經(jīng)安裝了Windows 10 ,你可以安裝虛擬機VMware,然后再安裝Windows 7,這樣就可以與Windows 10隔離。
2) 另一種是高級語言虛擬機(high-level language virtual machine,HLL VM),它們可以模擬硬件來運行二進(jìn)制碼,以消除語言對具體硬件的依賴,這就是我們本章所講的虛擬機。高級語言虛擬機又有基于
寄存器和
棧兩種。
基于寄存器的虛擬機現(xiàn)在來看C語言的語句:
a = b + c;
它的匯編指令可以用“三地址指令”表示:
這種三地址形式的指令集,
操作數(shù)通常放在寄存器中。在構(gòu)建虛擬機時,可以模擬這種情況,盡量使用物理寄存器,運算速度就會比較快。
基于棧的虛擬機可不可以有零地址的指令集呢?我們來看看Python的a = b + c語句, 其匯編碼為:
LOAD_NAME 0 (b)LOAD_NAME 1 (c)BINARY_ADDSTORE_NAME 2 (a)
這里BINARY_ADD(加法)指令是零地址指令,沒有任何操作數(shù),那它的操作數(shù)來自哪里?在哪里運算?結(jié)果存在哪里?帶著疑問,我們來一條條分析匯編碼:
1) LOAD_NAME 0 (b)
把符號元組的第0項b壓入求值棧,其實是把變量b引用的值壓入棧。不管了,為了講述方便,就簡單一點:
2) LOAD_NAME 1 (c)
把把符號元組的第1項c壓入求值棧:
3) BINARY_ADD
這條指令沒有操作數(shù),它依賴求值棧,即把棧頂?shù)那皟蓚€數(shù)據(jù)彈出,在CPU的運算單元中相加,然后將結(jié)果壓入棧中:
4) STORE_NAME 2 (a)
將棧頂?shù)闹祻棾鼋o變量a
從上面可以看出,零地址形式的指令集一般是通過“基于棧的架構(gòu)”實現(xiàn)的,
其指令的源與目標(biāo)都來自棧。一條零地址指令的寬度比多地址的要窄,因而可以用更少空間放下更多條指令。
但零地址指令要完成一件事情,通常會比多地址需要指令數(shù)更多。比如a = b + c語句,用一條多地址指令就可以完成,但卻需要4條零地址指令。所以一般來說,基于寄存器的虛擬機速度更快一些,原因是更多的指令條數(shù),意味著更多的內(nèi)存訪問次數(shù),而訪問內(nèi)存要花時間。
Python虛擬機基于棧 為啥Python采用了基于棧的架構(gòu)呢?主要有以下原因:
· 實現(xiàn)簡單 由于指令中不必顯式指定源與目標(biāo),使得編譯器和虛擬機的設(shè)計更加簡單,不必考慮為臨時變量分配空間的問題,求值過程中的臨時數(shù)據(jù)存儲都讓求值棧包辦就行。
· 更好的移植性不同處理器的特性各不相同:典型的復(fù)雜指令(CISC)處理器的通用寄存器數(shù)量很少,例如32位的x86就只有8個32位通用寄存器;精簡指令(RISC)處理器的寄存器數(shù)量多一些,例如ARM有16個32位通用寄存器。
對于一個基于寄存器的虛擬機,為了高效執(zhí)行指令,通常是把虛擬機中的寄存器映射到物理寄存器上。另外,有些很重要的輔助數(shù)據(jù)會被頻繁訪問,例如程序計數(shù)器(program counter,PC),它們也最好放在實際機器的物理寄存器中。如果虛擬機需要的寄存器數(shù)量比物理寄存器多,那就沒辦法全部映射,這樣實現(xiàn)起來比較麻煩,效率也會大打折扣。
而基于棧的虛擬機則簡單得多,它沒有硬性使用任何通用寄存器,所以可以自由分配物理寄存器,結(jié)果就是這樣的虛擬機可移植性更高。但作為優(yōu)化,基于棧的虛擬機的“求值棧”實際上也可以由編譯器映射到寄存器上,以減輕數(shù)據(jù)移動的開銷。
待續(xù)