23
2024
05
11:51:34

Python的虚拟机(virtual machine)

虚拟机(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_ADD
STORE_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),它们也最好放在实际机器的物理寄存器中。如果虚拟机需要的寄存器数量比物理寄存器多,那就没办法全部映射,这样实现起来比较麻烦,效率也会大打折扣。

而基于栈的虚拟机则简单得多,它没有硬性使用任何通用寄存器,所以可以自由分配物理寄存器,结果就是这样的虚拟机可移植性更高。但作为优化,基于栈的虚拟机的“求值栈”实际上也可以由编译器映射到寄存器上,以减轻数据移动的开销。




推荐本站淘宝优惠价购买喜欢的宝贝:

image.png

本文链接:https://hqyman.cn/post/6295.html 非本站原创文章欢迎转载,原创文章需保留本站地址!

分享到:
打赏





休息一下~~


« 上一篇 下一篇 »

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

请先 登录 再评论,若不是会员请先 注册

您的IP地址是: