在以太坊区块链的世界中,智能合约是自动执行的协议,而以太坊虚拟机(EVM)则是这些智能合约的运行环境,EVM的设计精巧且复杂,其中内存(Memory)作为一种关键且高效的存储资源,扮演着智能合约执行过程中“高速数据通道”的角色,理解EVM内存的存取机制,对于智能合约开发者优化性能、控制成本以及编写安全高效的代码至关重要。
EVM内存:是什么与为什么?

与持久化存储在区块链上的状态存储(State Storage,由存储槽位组成)不同,EVM内存是一种临时性、易失性的数据存储区域,它存在于智能合约执行期间,一旦合约执行结束,内存中的数据就会被清空,不会写入区块链,这种设计决定了内存的特性和用途:
EVM内存的组织与结构
EVM内存被组织成一个线性的字节数组(byte array),从地址0开始连续排列,内存的分配是“按需增长”的,初始大小为0,当合约需要访问超出当前内存大小的地址时,内存会进行扩展,内存扩展的代价相对较高,因为需要将新的内存页初始化为零,智能合约开发者通常会尽量减少内存扩展的次数,例如通过预先分配足够的内存空间。
内存的最小可寻址单位是字节(byte),EVM提供了一些操作码来以更高效的方式访问内存中的数据,例如按32字节(256位,一个字词word)进行读写。
EVM内存存取操作码
EVM提供了一系列操作码来对内存进行读写操作:
MLOAD (Memory Load):从内存中加载数据。

MLOAD offsetoffset地址开始,读取32字节(256位)的数据压入栈顶。MLOAD 0x20会将这32字节数据加载到栈中。MSTORE (Memory Store):将数据存储到内存中。
MSTORE offset valuevalue存储到内存offset地址开始的32字节空间中。PUSH1 0x10 PUSH1 0x00 MSTORE会将值0x10存储在内存地址0x00处(仅存储一个字节,其余31字节会被填充为0,因为PUSH1只推送1字节,实际MSTORE会扩展到32字节)。MSTORE8 (Memory Store 8 bits):存储单字节数据到内存。
MSTORE8 offset valueoffset地址处。PUSH1 0xAB PUSH1 0x00 MSTORE8会将字节0xAB存储在内存地址0x00。MSIZE (Memory Size):获取当前内存大小。
MSIZEMCOPY (Memory Copy):内存拷贝操作(由柏林硬分叉引入)。
MCOPY dest src sizesrc地址开始,拷贝size字节数据到内存dest地址,这是一个非常高效的操作,避免了多次MLOAD和MSTORE的开销。内存存取的应用场景
EVM内存在智能合约的执行中无处不在,主要用于:
变量存储与计算:在合约执行过程中,大量的中间计算结果、局部变量、函数参数等都会存储在内存中,以便快速访问和修改,在复杂的数学运算或数据处理算法中,内存用于暂存中间值。

数据编码与解码:与外部交互(如调用其他合约、接收ABI编码的数据)时,通常需要处理ABI编码的数据,内存用于存储这些编码的数据,并进行解码操作。abi.decode()函数内部就大量依赖内存操作。
哈希计算:如SHA3(Keccak-256)哈希计算,通常需要将待哈希的数据先加载到内存中,然后对内存区域进行哈希。SHA3操作码可以直接对内存区域进行哈希。
日志记录:虽然日志数据最终存储在区块链的收据中,但在构造日志主题和数据时,这些数据会先在内存中进行组装。
合约交互:在调用其他合约时,输入参数通常会先编码并存储在内存中,然后传递给被调用合约。
内存管理与Gas成本
虽然内存读写本身比状态存储便宜,但内存的扩展是有Gas成本的,EVM采用一种“分层”的Gas计算模型来惩罚内存的过度扩展:
优秀的智能合约开发者会:
PUSH <size> DUP1 MSTORE或更高效的PUSH <size> MSIZE DUP2 SUB DUP3 MSTORE等模式来预分配内存,避免多次扩展。内存与存储(Storage)及栈(Stack)的区别
为了更好地理解EVM内存,有必要将其与另外两个关键数据区——存储(Storage)和栈(Stack)进行区分: