Python的虚拟机(virtual machine)~1
时间:2023-07-01 05:30:02 | 来源:网站运营
时间:2023-07-01 05:30:02 来源:网站运营
Python的虚拟机(virtual machine)~1:
虚拟机(virtual machine)我们经常会遇到虚拟机这个概念,但不同的场合其含义却不相同:
1) 一种是用软件模拟整个机器的硬件系统,有了这个软件你相当于多了一台裸机,然后你就可以在里面装操作系统。比如,你的电脑已经安装了Windows 10 ,你可以安装虚拟机VMware,然后再安装Windows 7,这样就可以与Windows 10隔离。
2) 另一种是高级语言虚拟机(high-level language virtual machine,HLL VM),它们可以模拟硬件来运行二进制码,以消除语言对具体硬件的依赖,这就是我们本章所讲的虚拟机。高级语言虚拟机又有基于
寄存器和
栈两种。
基于寄存器的虚拟机现在来看C语言的语句:
a = b + c;
它的汇编指令可以用“三地址指令”表示:
这种三地址形式的指令集,
操作数通常放在寄存器中。在构建虚拟机时,可以模拟这种情况,尽量使用物理寄存器,运算速度就会比较快。
基于栈的虚拟机可不可以有零地址的指令集呢?我们来看看Python的a = b + c语句, 其汇编码为:
LOAD_NAME 0 (b)LOAD_NAME 1 (c)BINARY_ADDSTORE_NAME 2 (a)
这里BINARY_ADD(加法)指令是零地址指令,没有任何操作数,那它的操作数来自哪里?在哪里运算?结果存在哪里?带着疑问,我们来一条条分析汇编码:
1) LOAD_NAME 0 (b)
把符号元组的第0项b压入求值栈,其实是把变量b引用的值压入栈。不管了,为了讲述方便,就简单一点:
2) LOAD_NAME 1 (c)
把把符号元组的第1项c压入求值栈:
3) BINARY_ADD
这条指令没有操作数,它依赖求值栈,即把栈顶的前两个数据弹出,在CPU的运算单元中相加,然后将结果压入栈中:
4) STORE_NAME 2 (a)
将栈顶的值弹出给变量a
从上面可以看出,零地址形式的指令集一般是通过“基于栈的架构”实现的,
其指令的源与目标都来自栈。一条零地址指令的宽度比多地址的要窄,因而可以用更少空间放下更多条指令。
但零地址指令要完成一件事情,通常会比多地址需要指令数更多。比如a = b + c语句,用一条多地址指令就可以完成,但却需要4条零地址指令。所以一般来说,基于寄存器的虚拟机速度更快一些,原因是更多的指令条数,意味着更多的内存访问次数,而访问内存要花时间。
Python虚拟机基于栈 为啥Python采用了基于栈的架构呢?主要有以下原因:
· 实现简单 由于指令中不必显式指定源与目标,使得编译器和虚拟机的设计更加简单,不必考虑为临时变量分配空间的问题,求值过程中的临时数据存储都让求值栈包办就行。
· 更好的移植性不同处理器的特性各不相同:典型的复杂指令(CISC)处理器的通用寄存器数量很少,例如32位的x86就只有8个32位通用寄存器;精简指令(RISC)处理器的寄存器数量多一些,例如ARM有16个32位通用寄存器。
对于一个基于寄存器的虚拟机,为了高效执行指令,通常是把虚拟机中的寄存器映射到物理寄存器上。另外,有些很重要的辅助数据会被频繁访问,例如程序计数器(program counter,PC),它们也最好放在实际机器的物理寄存器中。如果虚拟机需要的寄存器数量比物理寄存器多,那就没办法全部映射,这样实现起来比较麻烦,效率也会大打折扣。
而基于栈的虚拟机则简单得多,它没有硬性使用任何通用寄存器,所以可以自由分配物理寄存器,结果就是这样的虚拟机可移植性更高。但作为优化,基于栈的虚拟机的“求值栈”实际上也可以由编译器映射到寄存器上,以减轻数据移动的开销。
待续