Solidity 是如何使用内存的?
Solidity 将地址 [0x00 - 0x20) 和 [0x20 - 0x40) 分配为哈希操作的“临时空间”。
Solidity 预留地址 [0x40 - 0x60) 作为“空闲内存指针”,通常指向当前未被使用的内存区域。
地址 [0x60 - 0x80) 保持为空,作为 32 字节的零值插槽,用于需要零值的场合。
内存使用从 [0x80 - ...) 开始。
Solidity 使用内存的场景:
abi.encode
和 abi.encodePacked
.memory
关键字)。memory
关键字的结构体或数组。在 Yul 中,
contract Memory {
struct Point {
uint256 x;
uint256 y;
}
event MemoryPointer(bytes32);
event MemoryPointerMsize(bytes32, bytes32);
function memPointerV1() external {
bytes32 x40;
assembly {
x40 := mload(0x40)
}
emit MemoryPointer(x40); // 0x0000000000000000000000000000000000000000000000000000000000000080
Point memory p = Point({x: 1, y: 2});
assembly {
x40 := mload(0x40)
}
emit MemoryPointer(x40); // 0x00000000000000000000000000000000000000000000000000000000000000c0
}
}
通过以上代码可以看出,“空闲内存指针”本来指向 0x80,分配了结构体后,指向了 0xc0。这个差值为 64 字节,即 2 个 32 字节,正好是结构体中的 x
和 y
。
function memPointerV2() external {
bytes32 x40;
bytes32 _msize;
assembly {
x40 := mload(0x40)
_msize := msize()
}
emit MemoryPointerMsize(x40, _msize);
// 0x0000000000000000000000000000000000000000000000000000000000000080
// 0x0000000000000000000000000000000000000000000000000000000000000060
Point memory p = Point({x: 1, y: 2});
assembly {
x40 := mload(0x40)
_msize := msize()
}
emit MemoryPointerMsize(x40, _msize);
// 0x00000000000000000000000000000000000000000000000000000000000000c0
// 0x00000000000000000000000000000000000000000000000000000000000000c0
assembly {
pop(mload(0xff))
x40 := mload(0x40)
_msize := msize()
}
emit MemoryPointerMsize(x40, _msize);
// 0x00000000000000000000000000000000000000000000000000000000000000c0
// 0x0000000000000000000000000000000000000000000000000000000000000120
}
msize()
返回最大可访问的内存地址。当内存中未存放数据时,该值为 0x60;而当存放了一个结构体后,该值与“空闲内存指针”的值一致,为 0xc0。
在最后一部分代码中使用 pop(mload(0xff))
的主要目的是为了读取内存槽 0xff 的数据,即[0xff - 0x120),让可访问空间变大,因此此时 msize()
变为 0x120。
function fixedArray() external {
bytes32 x40;
assembly {
x40 := mload(0x40)
}
e...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!