跳到主要内容
区块链Mar 28, 2026

Deep EVM #2:内存模型——栈、内存、存储和Calldata

OS
Open Soft Team

Engineering Team

数据可以存放的四个位置

EVM提供四个不同的数据位置,每个在成本、生命周期和访问模式上有着根本性差异。选择错误的位置是智能合约过度gas消耗的最常见原因。

位置生命周期读取成本写入成本大小
当前操作码0(DUP: 3)0(PUSH: 3)1024个字
内存当前调用上下文MLOAD: 3*MSTORE: 3*可扩展
存储永久(区块链)SLOAD: 2100/100SSTORE: 20000/2900/1002^256个槽
Calldata当前调用上下文CALLDATALOAD: 3只读交易输入

*内存每次操作消耗3 gas加上二次扩展成本。

栈:快速但小巧

栈是EVM的工作内存。每次算术、比较和逻辑操作都从栈中读写。它最多容纳1024个元素,每个32字节宽。

在实践中,你很少使用超过16个栈槽,因为DUP和SWAP操作码只能达到16个元素深度。

内存:便宜但短暂

内存是一个按字节寻址的数组,起始为空并按需扩展。它仅在当前调用上下文期间持续存在。

空闲内存指针

Solidity保留内存的前128字节用于特殊目的。0x40-0x5f处的空闲内存指针追踪下一个可用的内存地址。

内存扩展成本

内存的gas成本不仅是每次MLOAD/MSTORE的3 gas——当访问超出当前最高水位线的内存时,会收取二次扩展成本:

memory_cost = (memory_size_words^2 / 512) + (3 * memory_size_words)

存储:永久但昂贵

存储是EVM的持久化键值存储。每个合约有其独立的2^256个32字节槽的存储空间。

Solidity中的存储布局

Solidity按顺序将状态变量分配到存储槽,并在可能时将多个小变量打包到同一个槽中。

Calldata:只读且便宜

Calldata是交易或调用发送的输入数据。它是只读的,访问便宜(CALLDATALOAD消耗3 gas)。

瞬态存储(EIP-1153)

EIP-1153(Cancun升级,2024年3月)引入了TSTORE和TLOAD操作码。瞬态存储类似普通存储,但在交易结束时自动清除。每次TLOAD和TSTORE仅消耗100 gas。

总结

EVM的内存模型看似简单——四个有明确取舍的位置。但成本差异巨大:栈ADD消耗3 gas而SSTORE消耗20000 gas。深刻理解这些成本是区分gas高效合约与gas浪费合约的关键。