当前位置: 首页 > news >正文

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 消耗:相较于 storagememory 的读写操作消耗较少的 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 中不同的数据类型占用的存储空间不同,选择合适的数据类型可以节省存储空间。例如,尽量使用 uint8uint16 等小类型代替 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 中&#xff0c;存储和内存管理是编写高效智能合约的关键组成部分。合约执行的每一步操作都可能涉及到数据的存储和读取&#xff0c;而这些操作对 gas 的消耗有很大影响。因此&#xff0c;理解 Solidity 的存储模型以及如何优化数据的管理对于合约的安全性、性能和成…...

机器学习篇-day02-KNN算法实现鸢尾花模型和手写数字识别模型

一. KNN简介 KNN思想 K-近邻算法&#xff08;K Nearest Neighbor&#xff0c;简称KNN&#xff09;。比如&#xff1a;根据你的“邻居”来推断出你的类别 KNN算法思想&#xff1a;如果一个样本在特征空间中的k 个最相似的样本中的大多数属于某一个类别&#xff0c;则该样本也属…...

【C++】STL--vector

1.vector的介绍 我们先来看看vector的文档介绍&#xff0c;实际中我们只要熟悉相关接口就好了。 成员函数 使用STL的三个境界&#xff1a;能用&#xff0c;明理&#xff0c;能扩展 &#xff0c;那么下面学习vector&#xff0c;我们也是按照这个方法去学习 2 vector的使用 v…...

Java使用Redis的详细教程

Redis是一个基于内存的key-value结构数据库&#xff0c;即非关系型数据库&#xff0c;具有高性能、丰富的数据类型、持久化、高可用性和分布式等特点。在Java项目中&#xff0c;Redis通常用于缓存、分布式锁、计数器、消息队列和排行榜等场景。以下是在Java中使用Redis的详细教…...

严重 Zimbra RCE 漏洞遭大规模利用(CVE-2024-45519)

攻击者正在积极利用 CVE-2024-45519&#xff0c;这是一个严重的 Zimbra 漏洞&#xff0c;该漏洞允许他们在易受攻击的安装上执行任意命令。 Proofpoint 的威胁研究人员表示&#xff0c;攻击始于 9 月 28 日&#xff0c;几周前&#xff0c;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…...

前端项目场景相关的面试题,包含验证码、图片存储、登录鉴权、动态路由、组件划分等项目场景实际的面试题

项目场景面试题 如何防止短信验证码被刷 问题场景 添加倒计时和图片滑动验证&#xff0c;避免不必要的资源浪费 发送短信验证码需要费用发送短信消耗服务器资源 公司的图片、视频、文件资源如何存储的 传统模式 分开存储到数据服务器&#xff0c;托管服务器到云端 缺点&…...

uniapp 上了原生的 echarts 图表插件了 兼容性还行

插件地址&#xff1a;echarts - DCloud 插件市场 兼容性这块儿不知道后期会不会支持其他浏览器 H5 的话建议可以用原生的不用这个插件...

共享单车轨迹数据分析:以厦门市共享单车数据为例(八)

副标题&#xff1a;基于POI数据的站点综合评价——以厦门市为例&#xff08;三&#xff09; 什么是优劣解距离法&#xff08;TOPSIS&#xff09;&#xff1f; 优劣解距离法&#xff08;Technique for Order Preference by Similarity to Ideal Solution&#xff0c;简称TOPSI…...

sentinel原理源码分析系列(二)-动态规则和transport

本文是sentinel原理源码分析系列第二篇&#xff0c;分析两个组件&#xff0c;动态配置和transport 动态规则 Sentinel提供动态规则机制&#xff0c;依赖配置中心&#xff0c;如nacos&#xff0c;zookeeper&#xff0c;组件支持动态配置&#xff0c;模板类型为规则&#xff0c;支…...

ubuntu切换源方式记录(清华源、中科大源、阿里源)

文章目录 前言一、中科大源二、清华源三、阿里源 前言 记录ubunut切换各个源的方式。 备注&#xff1a;更换源之后使用sudo apt-get update更新索引。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、中科大源 地址&#xff1a;https://mirrors.u…...

【10】纯血鸿蒙HarmonyOS NEXT星河版开发0基础学习笔记-泛型基础全解(泛型函数、泛型接口、泛型类)及参数、接口补充

序言&#xff1a; 本文详细讲解了关于ArkTs语言中的泛型&#xff0c;其中包含泛型函数、泛型接口、泛型约束、泛型类及其中参数的使用方法&#xff0c;补充了一部分接口相关的知识&#xff0c;包括接口的继承和具体实现&#xff0c;也写到了一些边边角角的小知识&#xff0c;剩…...

2024年09月CCF-GESP编程能力等级认证C++编程一级真题解析

本文收录于专栏《C++等级认证CCF-GESP真题解析》,专栏总目录:点这里。订阅后可阅读专栏内所有文章。 一、单选题(每题 2 分,共 30 分) 第 1 题 据有关资料,山东大学于1972年研制成功DJL-1计算机,并于1973年投入运行,其综合性能居当时全国第三位。DJL-1计算机运算控制…...

基于多维统计分析与GMM聚类的食品营养特征研究

1.项目背景 在当今社会&#xff0c;随着人们对健康和营养的日益关注&#xff0c;深入了解食品的营养成分及其对人体的影响变得越来越重要&#xff0c;本研究采用了多维度的分析方法&#xff0c;包括营养成分比较分析、统计检验、营养密度分析和高斯混合模型&#xff08;GMM&am…...

SkyWalking 告警功能

SkyWalking 告警功能是在 6.x 版本新增的,其核心由一组规则驱动,这些规则定义在config/alarm-settings.yml文件中。 告警规则 告警规则:它们定义了应该如何触发度量警报,应该考虑什么条件。Webhook(网络钩子):定义当警告触发时,哪些服务终端需要被告知。常用告警规则 …...

国内旅游:现状与未来趋势分析

在当今社会快速发展的背景下&#xff0c;国内旅游更是呈现出蓬勃的发展态势。中国&#xff0c;这片拥有悠久历史、灿烂文化和壮丽山河的广袤土地&#xff0c;为国内旅游的兴起与发展提供了得天独厚的条件。 本报告将借助 DataEase 强大的数据可视化分析能力&#xff0c;深入剖…...

西电25考研 VS 24考研专业课大纲变动汇总

01专业课变动 西安电子科技大学专业课学长看到953网络安全基础综合变为 893网络安全基础综合&#xff0c;这是因为工科要求都必须是8开头的专业课&#xff0c;里面参考课本还是没变的&#xff0c;无非就是变了一个名字 对于其他变动专业课也是同理的 02专业课考纲内容变化 对于…...

【Linux】进程管理:状态与优先级调度的深度分析

✨ 山海自有归期&#xff0c;风雨自有相逢 &#x1f30f; &#x1f4c3;个人主页&#xff1a;island1314 &#x1f525;个人专栏&#xff1a;Linux—登神长阶 ⛺️ 欢迎关注&#xff1a;&#x1f44d;点赞 &#x1…...

同轴电缆笔记

同轴电缆笔记 射频同轴电缆的阻抗标准为什么是50Ω或75Ω呢&#xff1f; 在PCB设计中&#xff0c;在合理的范围内&#xff0c;传输线阻抗的具体数值并不重要。只要控制好整条传输线的阻抗&#xff0c;不要出现阻抗不连续的情况就好了。设计中的其他因素往往决定了我们用什么样…...

【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL74

异步复位同步释放 描述 题目描述&#xff1a; 请使用异步复位同步释放来将输入数据a存储到寄存器中&#xff0c;并画图说明异步复位同步释放的机制原理 信号示意图&#xff1a; clk为时钟 rst_n为低电平复位 d信号输入 dout信号输出 波形示意图&#xff1a; 输入描…...

在Linux系统安装Nginx

注意&#xff1a;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 来喽

前言&#xff1a;C语言中有许多关键字&#xff08;关键字是预先保留的标识符&#xff0c;具有特殊意义&#xff0c;不能用作变量 名、函数名等普通标识符。&#xff09; 比如&#xff1a;前面在变量与常量那一节提到的extern 就是一个关键字&#xff0c;应该还记得e…...

Git版本控制工具--关于命令

Git版本控制工具 学习前言 在项目开发中&#xff0c;总是需要多个人同时对一个项目进行修改&#xff0c;如何高效快速地进行修改&#xff0c;且控制各自修改的版本不会和他人的进行重叠&#xff0c;这就需要用到Git分布式版本控制器了 作用 解决了一致性&#xff0c;并发性…...

【iOS】计算器的仿写

计算器 文章目录 计算器前言简单的四则运算UI界面事件的逻辑小结 前言 笔者应组内要求&#xff0c;简单实现了一个可以完成简单四则运算的计算器程序。UI界面则是通过最近学习的Masonry库来实现的&#xff0c;而简单的四则运算内容则是通过栈来实现一个简单的四则运算。 简单…...

报错 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的串口&#xff0c;其对应关系就是COMx对应WSL的/dev/ttySx&#xff0c;例如COM2对应WSL的/dev/ttyS2。WSL2是不支持USB设备的&#xff0c;但可以通过usbipd-win程序将windows上的usb设备映射到wsl2中&#xff0c;参考微软官方文档连接 USB …...

从原理到代码:如何通过 FGSM 生成对抗样本并进行攻击

从原理到代码&#xff1a;如何通过 FGSM 生成对抗样本并进行攻击 简介 在机器学习领域&#xff0c;深度神经网络的强大表现令人印象深刻&#xff0c;尤其是在图像分类等任务上。然而&#xff0c;随着对深度学习的深入研究&#xff0c;研究人员发现了神经网络的一个脆弱性&…...

从零开始学习OMNeT++系列第一弹——OMNeT++的介绍与安装

最近由于由于工作上的需求&#xff0c;接了一个网络仿真的任务。于是开始调研各个仿真平台&#xff0c;然后根据目前的需求和网络上公开资料的多少&#xff0c;决定使用omnet这个网络仿真平台。现在也是刚开始学习&#xff0c;所以决定记录一下从零开始的这个学习过程。因为虽然…...

Cluster Explanation via Polyhedral Descriptions

通过多面体描述进行聚类解释 本文关注聚类描述问题&#xff0c;即在给定数据集及其聚类划分的情况下&#xff0c;解释这些聚类的任务。我们提出了一种新的聚类解释方法&#xff0c;通过在每个聚类周围构建一个多面体&#xff0c;同时最小化最终多面体的复杂性或用于描述的特征…...

爬虫设计思考之一

爬虫设计思考之一 经常做爬虫的人对于技术比较的执着&#xff0c;尤其是本身从事的擅长的技术领域&#xff0c;从而容易忽视与之相近或者相似的技术。因此我建议大家在遇到此类问题的时候&#xff0c;可以采用对比分析的方式来理解。 本次的思考是基于国内最大的中文搜索引擎百…...

网站打开显示建设中/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 代表端口映射&#xff0c;格式为 宿主机映射端口:容器运行端口-e 代表添加环境变量 MYSQL_ROOT_PASSWORD 是 root 用户的登陆密码5.1.3 进入 MySQL 容器,登陆 MySQL进入 mysql 容器5.1.4 远程登…...

网站开发前段和后端/全国人大常委会

私家车最多可以开多少年&#xff1f;新的报废规则是这样规定的据统计&#xff0c;我国的机动车保有量已经突破了2.4亿辆&#xff0c;这意味着平均每7个人之中就有一个人有车&#xff0c;虽然汽车保有量那么大&#xff0c;但是大家又是否知道一辆私家车最多能开多少年呢&#xf…...

如何提高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. 为什么需要管理代码风格&#xff1f;2. 配置Beautifier&#xff1a;帮助 → 关于插件&#xff0c;勾选Beautifier&#xff0c;然后重启Qt3. 设置format3.1 获取clang-format.exe3.2 工具 → 选项3.3 Beautifier → General → 勾选Enable auto format on file save → 选…...