虚拟机的执行资源

以太坊的虚拟机经常被拿来与x86台式机的结构作对比,它们有相同点也有很大的不同点。

相比于台式机或者手机,以太坊的虚拟机更加紧凑,资源更加匮乏。 它并不包含正常的CPU 所具备的硬件寄存器(Register),所以执行速度没有这么快。 它的执行宽度都是 256bit 的固定长度值,所以相对比较容易编程,它包含了存储、堆栈、内存三大存储机构。

下图显示了以太坊的虚拟机的执行资源。

http://static.codebaoku.com/pics/1a/0b/1a0ba20faa8db1f98c5755dedc37710a.png

以太坊虚拟机的执行资源

Storage 存储

存储里的值都是永久记录在区块链上的。存储在写和读取上都代价昂贵,如非必须,则数据不要存储在存储区。 存储区是全世界计算机都会同步到硬盘上的区块链的一部分,哪怕关机以后也被永久记录。 那么哪些值需要保存在这里呢?只有那些需要在程序执行后任然留存的数字才需要, 例如以太坊的 ERC20 智能合约追踪 token 持有者和 token 数量的关系,这个数据需要持久化保存到存储区。

存储区的数据都是 256bit 的键和值配对存储,如下图所示。如果查询时一个键对应的值不存在,则它读取的值为 0 。 存储区的读写操作都是以 256bit 为单位的,没有更小的操作空间。故而 uint8 和 uint256 在单值存储的情况下占用的空间相同,耗费的 Gas 也相同。

将 unit8 包裹进入 struct 结构体以后可以通过优化来节约空间位置,节省 gas 支出。

http://static.codebaoku.com/pics/71/c6/71c65dac0151622e526c49be8d7b4a8f.png

存储 Storage 示意图,索引和值都是256位的数据

Stack 堆栈

堆栈的花费和内存差不多,堆栈往往保存了执行过程的上下文,如下图所示。 堆栈有且仅有 1024 层深度,当我们执行递归调用过多的时候,堆栈就会击穿 1024 层,则代码执行失败。这在其他编程语言中也是相同的原理。

堆栈仅有高处的 16 层是可以被快速访问的,堆栈的宽度也是 256bit,也就是 32byte,一个 word 的长度,任何读写操作都是 256bit 为一个单位进行的。 编译器往往会将代码执行中的临时变量、变量地址放到堆栈上临时保存,变量地址可以进一步索引到内存 Memory 中。

http://static.codebaoku.com/pics/8d/9e/8d9ecbd3f0ed66188385a457fc365c47.png

堆栈 Stack 示意图,数据都是256bit进出堆栈

Memory 内存

内存在以太坊虚拟机中和真实计算机的内存概念相近:一旦虚拟机启动,内存就处在不断变化之中,承载了程序运行时的指令和数据的保存。 一旦虚拟机执行结束并关机,内存保存的数据就会灰飞烟灭。

内存的管理办法也是按照 256bit 为单位进行读取和写入, 如下图所示。写入时候也可以选择 8bit 为单位写入,因为内存的宽度是 8bit。内存的读取和写入都相对其他两种存储而言更便宜。

举例来说,读取和写入一个 256bit的值花费仅有 3Gas,是 Storage 存储区的写操作的万分之一多一点。

http://static.codebaoku.com/pics/09/93/099317573a1762e98714277009ab6b94.png

内存 Memory,合约执行完毕就会自动清空

合约还能被合约调用吗?是的,可以。在以太坊中执行代码的一台虚拟机可以启动另一台虚拟机来执行部分指令。这两台虚拟机都将在一个挖矿节点上运行,形成多线程并行。这称之为“合约调用合约”。 常见的合约调用合约的 ...