区块链中维护大数组的gas成本是否高于删除冗余元素缩容的成本?
两种方案gas成本对比结论
绝大多数场景下,主动删除冗余元素的总体gas成本更低,具体分析如下:
核心成本计算依据(基于Solidity 0.5.16对应EVM版本的gas规则)
- 存储删除退款规则:将非0存储槽改为0时,每个槽可获得15000 gas退款,退款上限为本次交易总gas消耗的50%
- 存储读取成本:单次SLOAD操作消耗200 gas
- 存储写入成本:非0值修改为非0值单次SSTORE消耗5000 gas,0值修改为非0值单次SSTORE消耗20000 gas
两种方案成本对比
1. 主动删除冗余元素的成本
你当前的删除逻辑对应操作的净成本极低:
- 执行
delete example_array[m]时,会清空该子数组对应的5个存储槽(1个存储子数组长度的槽+4个uint256元素槽),共可获得5 * 15000 = 75000gas退款 - 清空槽的SSTORE成本为
5 * 5000 = 25000gas,修改数组长度的SSTORE成本为5000 gas,合计消耗30000 gas - 净成本为
30000 - 75000 = -45000gas,也就是删除单个冗余元素不仅不会额外花钱,还能获得gas退款
注意:你当前的删除代码存在逻辑缺陷,如果
m不是数组的最后一位索引,直接length--会丢失数组最后一位的有效元素,正确的中间元素删除写法为:if (m != example_array.length - 1) { example_array[m] = example_array[example_array.length - 1]; } delete example_array[example_array.length - 1]; example_array.length--;即便增加了将末尾元素挪到
m位置的写入操作,新增成本仅约5000 gas,删除操作整体依然是净收益。
2. 保留冗余元素的额外成本
每多一个冗余元素,每次调用f函数都会多执行一次循环:
- 单次循环最少需要读取数组长度、读取对应索引的子数组指针,至少消耗~1000 gas
- 如果你的业务逻辑需要读取子数组内的元素,单次循环额外成本会上升到~2000 gas
- 只要
f函数被调用≥2次,多消耗的gas就会超过删除冗余元素的所有支出
适用例外场景
只有当f函数总共只会被调用1次,且后续不会再操作该数组时,保留冗余元素的成本才会更低,这种场景在实际业务中几乎不存在。
内容的提问来源于stack exchange,提问作者Senses
相关产品推荐
相关产品推荐

