Solidity 存储和内存管理:深入理解与高效优化
在 Solidity 中,存储和内存管理是编写高效智能合约的关键组成部分。合约执行的每一步操作都可能涉及到数据的存储和读取,而这些操作对 gas 的消耗有很大影响。因此,理解 Solidity 的存储模型以及如何优化数据的管理对于合约的安全性、性能和成本至关重要。
1. Solidity 中的存储模型概述
Solidity 的存储模型主要由三个关键概念组成:存储(storage)、内存(memory) 和 数据传递(calldata)。这三者负责智能合约中的数据存储与管理,它们有不同的用途和特性,对 gas 的消耗也不同。
1.1 存储(storage)
storage
是 Solidity 中持久化的数据存储位置。所有在合约中定义的状态变量(即合约的成员变量)都存储在 storage
中。这意味着即使合约执行结束或区块链状态发生变化,storage
中的数据依然保持不变,直到合约显式修改它。
- 永久存储:状态变量存储在
storage
中,数据不会在函数执行完毕后丢失。 - 较高的 gas 消耗:因为存储在区块链的永久存储中,读写操作会消耗较多的 gas,特别是写操作。
示例:
contract StorageExample {uint256 public data; // 存储在 storage 中的状态变量function updateData(uint256 _data) public {data = _data; // 修改 storage 中的数据,消耗较多 gas}
}
1.2 内存(memory)
memory
是用于临时存储数据的非持久化存储区域。函数调用时,局部变量、函数参数等可以存储在 memory
中。memory
中的数据只在函数执行期间存在,函数返回后数据会被清除。
- 临时存储:
memory
中的数据不会在函数执行结束后保留。 - 相对较低的 gas 消耗:相较于
storage
,memory
的读写操作消耗较少的 gas。
示例:
contract MemoryExample {function process(uint256 _input) public pure returns (uint256) {uint256 temp = _input * 2; // 临时存储在 memory 中return temp; // 函数执行完毕后,temp 将被清除}
}
1.3 数据传递(calldata)
calldata
是一个特殊的存储区域,用于存储函数的外部调用参数。calldata
是不可修改的(只读),而且 gas 消耗更低,因此常用于处理外部输入的数据。
- 只读存储:
calldata
中的数据不能被修改,通常用于传递外部函数调用参数。 - 最低的 gas 消耗:由于它的只读属性,
calldata
的读写操作 gas 消耗最低。
示例:
contract CalldataExample {function processCalldata(uint256[] calldata data) public pure returns (uint256) {return data[0] * 2; // 只读访问 calldata 中的数据}
}
2. 存储、内存和数据传递的区别
2.1 生命周期
- 存储(storage):与合约的生命周期一致,数据在合约的整个生命周期内都保留,直到显式修改或删除。
- 内存(memory):仅在函数调用期间存在,函数结束后内存会自动释放,数据不再保留。
- 数据传递(calldata):函数调用期间的只读数据存储,用于外部合约调用参数传递,函数执行完毕后数据消失。
2.2 可读写性
- 存储(storage):可读可写,适用于需要长期存储和操作的数据。
- 内存(memory):可读可写,适用于临时数据处理,但不能用于永久存储。
- 数据传递(calldata):只读,适用于只需要读取外部传递的数据场景。
2.3 gas 消耗
- 存储(storage):写操作消耗最高,读操作次之,主要用于需要长期保存数据的场景。
- 内存(memory):读写操作的 gas 消耗比
storage
低,适合函数内部临时处理数据。 - 数据传递(calldata):消耗最少,特别适合只需要传递和读取外部数据的场景。
3. 如何高效管理数据?
3.1 优化存储访问
- 减少
storage
写操作:由于写入storage
的操作非常昂贵,应该尽可能减少不必要的storage
写入。可以通过局部变量临时保存值,并在所有计算完成后再更新storage
。
示例:
contract OptimizedStorage {uint256 public data;function updateData(uint256 _input) public {uint256 temp = data; // 读取 storage 到局部变量temp += _input; // 在内存中处理data = temp; // 完成处理后再更新 storage}
}
在上面的代码中,我们将 storage
中的 data
读取到 memory
中,并在所有处理完成后再写回 storage
。这样减少了多次 storage
写入,从而节省 gas。
3.2 使用 calldata
传递数据
如果函数参数是外部传入的数组或字符串,尽量使用 calldata
,因为它的 gas 消耗最少。如果数据只用于读取,而不需要修改,calldata
是最佳选择。
示例:
contract UseCalldata {function sumArray(uint256[] calldata data) public pure returns (uint256) {uint256 sum = 0;for (uint256 i = 0; i < data.length; i++) {sum += data[i]; // 只读访问 calldata 数据}return sum;}
}
3.3 合适的数据类型选择
Solidity 中不同的数据类型占用的存储空间不同,选择合适的数据类型可以节省存储空间。例如,尽量使用 uint8
、uint16
等小类型代替 uint256
,如果数据范围允许的话。
3.4 减少复杂数据结构的存储
复杂的数据结构(如数组、映射等)在 storage
中占用更多的存储空间并且消耗更多的 gas。在设计合约时,应尽量减少复杂数据结构的使用,或者将其临时保存在 memory
中处理。
4. 存储、内存和数据传递的常见误区
4.1 将数组保存在 storage
中
将数组保存在 storage
中并进行频繁操作是一个常见的低效操作。数组的长度会影响读取、修改等操作的 gas 消耗,尤其是对于大数组,频繁操作会显著增加成本。因此,建议将数组数据尽量在 memory
中处理,并在必要时再将结果写回 storage
。
4.2 不当的 calldata
使用
虽然 calldata
消耗最低,但它只能用于外部调用的参数。如果尝试在函数内部创建或修改 calldata
,编译器会报错。因此,calldata
只能用于只读场景,开发者需要清楚它的限制。
5. 总结
理解 Solidity 中的存储模型和数据管理对于优化合约性能和降低 gas 成本至关重要。存储(storage)用于持久化数据,操作消耗较高;内存(memory)适用于临时数据处理,消耗较低;而数据传递(calldata)是用于函数参数的高效只读存储。为了编写高效的合约,开发者应根据具体需求合理选择存储区域,并尽量减少不必要的 storage
写操作。
相关文章:
Solidity 存储和内存管理:深入理解与高效优化
在 Solidity 中,存储和内存管理是编写高效智能合约的关键组成部分。合约执行的每一步操作都可能涉及到数据的存储和读取,而这些操作对 gas 的消耗有很大影响。因此,理解 Solidity 的存储模型以及如何优化数据的管理对于合约的安全性、性能和成…...
机器学习篇-day02-KNN算法实现鸢尾花模型和手写数字识别模型
一. KNN简介 KNN思想 K-近邻算法(K Nearest Neighbor,简称KNN)。比如:根据你的“邻居”来推断出你的类别 KNN算法思想:如果一个样本在特征空间中的k 个最相似的样本中的大多数属于某一个类别,则该样本也属…...
【C++】STL--vector
1.vector的介绍 我们先来看看vector的文档介绍,实际中我们只要熟悉相关接口就好了。 成员函数 使用STL的三个境界:能用,明理,能扩展 ,那么下面学习vector,我们也是按照这个方法去学习 2 vector的使用 v…...
Java使用Redis的详细教程
Redis是一个基于内存的key-value结构数据库,即非关系型数据库,具有高性能、丰富的数据类型、持久化、高可用性和分布式等特点。在Java项目中,Redis通常用于缓存、分布式锁、计数器、消息队列和排行榜等场景。以下是在Java中使用Redis的详细教…...
严重 Zimbra RCE 漏洞遭大规模利用(CVE-2024-45519)
攻击者正在积极利用 CVE-2024-45519,这是一个严重的 Zimbra 漏洞,该漏洞允许他们在易受攻击的安装上执行任意命令。 Proofpoint 的威胁研究人员表示,攻击始于 9 月 28 日,几周前,Zimbra 开发人员发布了针对 CVE-2024-…...
php函数积累
对称函数 isset 判断数组arr中是否存在键key 返回值true/false isset(name,$arr) unset 删除数组中的键 需存在key不然抛出异常 unset($arr[name]) json_encode 数据转json格式 json_encode($arr) 一般形式 指定字符编码形式 json_decode json格式转原有数据格式 json_d…...
前端项目场景相关的面试题,包含验证码、图片存储、登录鉴权、动态路由、组件划分等项目场景实际的面试题
项目场景面试题 如何防止短信验证码被刷 问题场景 添加倒计时和图片滑动验证,避免不必要的资源浪费 发送短信验证码需要费用发送短信消耗服务器资源 公司的图片、视频、文件资源如何存储的 传统模式 分开存储到数据服务器,托管服务器到云端 缺点&…...
uniapp 上了原生的 echarts 图表插件了 兼容性还行
插件地址:echarts - DCloud 插件市场 兼容性这块儿不知道后期会不会支持其他浏览器 H5 的话建议可以用原生的不用这个插件...
共享单车轨迹数据分析:以厦门市共享单车数据为例(八)
副标题:基于POI数据的站点综合评价——以厦门市为例(三) 什么是优劣解距离法(TOPSIS)? 优劣解距离法(Technique for Order Preference by Similarity to Ideal Solution,简称TOPSI…...
sentinel原理源码分析系列(二)-动态规则和transport
本文是sentinel原理源码分析系列第二篇,分析两个组件,动态配置和transport 动态规则 Sentinel提供动态规则机制,依赖配置中心,如nacos,zookeeper,组件支持动态配置,模板类型为规则,支…...
ubuntu切换源方式记录(清华源、中科大源、阿里源)
文章目录 前言一、中科大源二、清华源三、阿里源 前言 记录ubunut切换各个源的方式。 备注:更换源之后使用sudo apt-get update更新索引。 提示:以下是本篇文章正文内容,下面案例可供参考 一、中科大源 地址:https://mirrors.u…...
【10】纯血鸿蒙HarmonyOS NEXT星河版开发0基础学习笔记-泛型基础全解(泛型函数、泛型接口、泛型类)及参数、接口补充
序言: 本文详细讲解了关于ArkTs语言中的泛型,其中包含泛型函数、泛型接口、泛型约束、泛型类及其中参数的使用方法,补充了一部分接口相关的知识,包括接口的继承和具体实现,也写到了一些边边角角的小知识,剩…...
2024年09月CCF-GESP编程能力等级认证C++编程一级真题解析
本文收录于专栏《C++等级认证CCF-GESP真题解析》,专栏总目录:点这里。订阅后可阅读专栏内所有文章。 一、单选题(每题 2 分,共 30 分) 第 1 题 据有关资料,山东大学于1972年研制成功DJL-1计算机,并于1973年投入运行,其综合性能居当时全国第三位。DJL-1计算机运算控制…...
基于多维统计分析与GMM聚类的食品营养特征研究
1.项目背景 在当今社会,随着人们对健康和营养的日益关注,深入了解食品的营养成分及其对人体的影响变得越来越重要,本研究采用了多维度的分析方法,包括营养成分比较分析、统计检验、营养密度分析和高斯混合模型(GMM&am…...
SkyWalking 告警功能
SkyWalking 告警功能是在 6.x 版本新增的,其核心由一组规则驱动,这些规则定义在config/alarm-settings.yml文件中。 告警规则 告警规则:它们定义了应该如何触发度量警报,应该考虑什么条件。Webhook(网络钩子):定义当警告触发时,哪些服务终端需要被告知。常用告警规则 …...
国内旅游:现状与未来趋势分析
在当今社会快速发展的背景下,国内旅游更是呈现出蓬勃的发展态势。中国,这片拥有悠久历史、灿烂文化和壮丽山河的广袤土地,为国内旅游的兴起与发展提供了得天独厚的条件。 本报告将借助 DataEase 强大的数据可视化分析能力,深入剖…...
西电25考研 VS 24考研专业课大纲变动汇总
01专业课变动 西安电子科技大学专业课学长看到953网络安全基础综合变为 893网络安全基础综合,这是因为工科要求都必须是8开头的专业课,里面参考课本还是没变的,无非就是变了一个名字 对于其他变动专业课也是同理的 02专业课考纲内容变化 对于…...
【Linux】进程管理:状态与优先级调度的深度分析
✨ 山海自有归期,风雨自有相逢 🌏 📃个人主页:island1314 🔥个人专栏:Linux—登神长阶 ⛺️ 欢迎关注:👍点赞 …...
同轴电缆笔记
同轴电缆笔记 射频同轴电缆的阻抗标准为什么是50Ω或75Ω呢? 在PCB设计中,在合理的范围内,传输线阻抗的具体数值并不重要。只要控制好整条传输线的阻抗,不要出现阻抗不连续的情况就好了。设计中的其他因素往往决定了我们用什么样…...
【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL74
异步复位同步释放 描述 题目描述: 请使用异步复位同步释放来将输入数据a存储到寄存器中,并画图说明异步复位同步释放的机制原理 信号示意图: clk为时钟 rst_n为低电平复位 d信号输入 dout信号输出 波形示意图: 输入描…...
在Linux系统安装Nginx
注意:Nginx端口号是80(云服务器要放行) 我的是基于yum源安装 安装yum源(下面这4步就好了) YUM源 1、将源文件备份 cd /etc/yum.repos.d/ && mkdir backup && mv *repo backup/ 2、下载阿里源文件 curl -o /etc/yum.repos.d/CentOS-Base.repo ht…...
C初阶(六)--- static 来喽
前言:C语言中有许多关键字(关键字是预先保留的标识符,具有特殊意义,不能用作变量 名、函数名等普通标识符。) 比如:前面在变量与常量那一节提到的extern 就是一个关键字,应该还记得e…...
Git版本控制工具--关于命令
Git版本控制工具 学习前言 在项目开发中,总是需要多个人同时对一个项目进行修改,如何高效快速地进行修改,且控制各自修改的版本不会和他人的进行重叠,这就需要用到Git分布式版本控制器了 作用 解决了一致性,并发性…...
【iOS】计算器的仿写
计算器 文章目录 计算器前言简单的四则运算UI界面事件的逻辑小结 前言 笔者应组内要求,简单实现了一个可以完成简单四则运算的计算器程序。UI界面则是通过最近学习的Masonry库来实现的,而简单的四则运算内容则是通过栈来实现一个简单的四则运算。 简单…...
报错 libgomp.so.1, needed by vendor/llama.cpp/ggml/src/libggml.so, not found
在安装 xinference时报错 安装命令 pip install "xinference[all]" 报错内容 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.2/1.2 MB 3.7 MB/s eta 0:00:00 INFO: pip is looking at multiple versions of multiprocess t…...
wsl(3) -- USB使用
1. 简介 WSL1中可以直接使用Windows的串口,其对应关系就是COMx对应WSL的/dev/ttySx,例如COM2对应WSL的/dev/ttyS2。WSL2是不支持USB设备的,但可以通过usbipd-win程序将windows上的usb设备映射到wsl2中,参考微软官方文档连接 USB …...
从原理到代码:如何通过 FGSM 生成对抗样本并进行攻击
从原理到代码:如何通过 FGSM 生成对抗样本并进行攻击 简介 在机器学习领域,深度神经网络的强大表现令人印象深刻,尤其是在图像分类等任务上。然而,随着对深度学习的深入研究,研究人员发现了神经网络的一个脆弱性&…...
从零开始学习OMNeT++系列第一弹——OMNeT++的介绍与安装
最近由于由于工作上的需求,接了一个网络仿真的任务。于是开始调研各个仿真平台,然后根据目前的需求和网络上公开资料的多少,决定使用omnet这个网络仿真平台。现在也是刚开始学习,所以决定记录一下从零开始的这个学习过程。因为虽然…...
Cluster Explanation via Polyhedral Descriptions
通过多面体描述进行聚类解释 本文关注聚类描述问题,即在给定数据集及其聚类划分的情况下,解释这些聚类的任务。我们提出了一种新的聚类解释方法,通过在每个聚类周围构建一个多面体,同时最小化最终多面体的复杂性或用于描述的特征…...
爬虫设计思考之一
爬虫设计思考之一 经常做爬虫的人对于技术比较的执着,尤其是本身从事的擅长的技术领域,从而容易忽视与之相近或者相似的技术。因此我建议大家在遇到此类问题的时候,可以采用对比分析的方式来理解。 本次的思考是基于国内最大的中文搜索引擎百…...
网站打开显示建设中/seo关键词词库
目录 一、基本概念 1.1 什么是赫夫曼树 1.2 什么是权值 1.3 什么是路径 1.4 什么是带权路径长度(WPL) 1.5 举例说明 二、如何构建赫夫曼树 2.1 明确给定值 2.2 明确赫夫曼树的特点 2.3 实现赫夫曼树 2.4 关于实现赫夫曼树过程中的一点理解 三、赫夫曼树…...
开发一个软件流程/招聘seo专员
5.部署应用5.1 MySQL 部署5.1.1 拉取 MySQL 镜像查看镜像5.1.2 创建 MySQL 容器-p 代表端口映射,格式为 宿主机映射端口:容器运行端口-e 代表添加环境变量 MYSQL_ROOT_PASSWORD 是 root 用户的登陆密码5.1.3 进入 MySQL 容器,登陆 MySQL进入 mysql 容器5.1.4 远程登…...
网站开发前段和后端/全国人大常委会
私家车最多可以开多少年?新的报废规则是这样规定的据统计,我国的机动车保有量已经突破了2.4亿辆,这意味着平均每7个人之中就有一个人有车,虽然汽车保有量那么大,但是大家又是否知道一辆私家车最多能开多少年呢…...
如何提高wordpress的反应速度/网络营销专业就业方向
TM1637简单时钟仿真 在前面的文章中,我们使用ATtiny13成功驱动了TM1637,在本次实例中,将实现一个简单的时钟。 在前面的文章中,对TM1637的驱动及应用做了详细的介绍,请参考: ATtiny13与Proteus仿真-TM1637驱动仿真 ESP8266-Arduino编程实例-TM1637-驱动4位7段数码管 ES…...
网站自己做的记者证/淘宝流量助手平台
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧文章目录 最近更新的博客使用说明求字…...
用discuz做行业网站/网站优化公司哪个好
目录1. 为什么需要管理代码风格?2. 配置Beautifier:帮助 → 关于插件,勾选Beautifier,然后重启Qt3. 设置format3.1 获取clang-format.exe3.2 工具 → 选项3.3 Beautifier → General → 勾选Enable auto format on file save → 选…...