Solidity ConstantOptimiser优化疑问:为何分解address(0xAAAA)而非直接推送?
Solidity常量优化的Gas疑惑
我在Remix IDE中开启optimize=true调试时,发现Solidity代码address(0xAAAA)生成了以下opcode,实际是在计算20字节的1:
PUSH1 0x1 PUSH1 0x1 PUSH1 0xa0 SHL SUB
我在Solidity仓库的ConstantOptimiser.cpp文件中找到findRepresentation方法,它会分解大于255的常量。这种方式消耗的gas难道不比直接推送常量更多吗?为何要执行该优化?
核心原因:优先优化部署字节码成本
这种优化的本质是牺牲少量运行时Gas,换取部署时的字节码大小成本节省,而后者在很多场景下收益更高:
1. 字节码长度的部署成本差异
- 直接推送20字节的常量(比如
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)需要用PUSH20指令,对应的字节码总长度是21字节(1字节的PUSH20操作码 + 20字节的常量值),部署时每字节收费200Gas,总成本是21 × 200 = 4200 Gas。 - 而生成的计算式opcode总长度仅8字节:3个
PUSH1(每个2字节) +SHL(1字节) +SUB(1字节),部署成本是8 × 200 = 1600 Gas,直接节省2600 Gas的部署成本。
2. 运行时Gas的权衡
运行时的Gas消耗确实会增加:
- 直接推送的
PUSH20仅消耗3 Gas; - 计算式的5条指令总共消耗
3×3 + 3 + 3 = 15 Gas。
但优化器的逻辑是:部署成本是一次性的固定支出,而运行时Gas只有在合约被调用时才会产生。如果合约不是高频调用该常量,或者部署次数远多于调用次数(比如工厂合约批量创建子合约),这种优化的整体收益是正的。
3. 优化器的决策逻辑
Solidity的ConstantOptimiser会针对不同常量的大小、使用频率等维度做权衡:
- 对于小常量(≤255),直接用
PUSH1推送更高效; - 对于大常量,若使用次数少,优先用计算式压缩字节码;若使用次数多,则可能将常量存入合约存储或内存,避免重复计算。
内容的提问来源于stack exchange,提问作者Zoey
相关产品推荐
相关产品推荐

