Redis学习笔记:简单动态字符串

news2025/2/23 23:01:26

简单动态字符串

        C语言传统的字符串是使用字符数组表示的,Redis没有直接使用C语言传统的字符串表示,而是构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类型,并将SDS作为Redis的默认字符串。

SDS的实现

        SDS使用sds.h/sdshdr结构表示,len表示字符串的长度,free是数组中未使用字节的数量,buf是保存字符串的字节数组。SDS遵循C字符串以空字符结尾的惯例,保存空字符的1字节空间不计算在SDS的len属性里面,并且为空字符分配额外的1字节空间,以及添加空字符到字符串末尾等操作,都是由SDS函数自动完成的,好处是,SDS可以直接重用一部分C字符串函数库里面的函数。

//抽象类型SDS
struct sdshdr  {
    int len;//字符串长度len
    int free;//记录buf数组中未使用字节的数量
    char buf[];//保存字符串的字节数组
};

如图展示了2个SDS示例:

这两个SDS都保存着字符串"Redis",第一个没有未使用空间,第二个分配了5个字节的未使用空间。

SDS与C字符串的区别

常数复杂度获取字符串长度

        因为C字符串并不记录自身的长度信息,所以为了获取一个C字符串的长度,程序必须遍历整个字符串数组,对遇到的每个字符进行计数,直到遇到代表字符串结尾的空字符为止,这个操作的时间复杂度为O(N)。和C字符串不同,因为SDS在len属性中记录了SDS本身的长度,所以获取一个SDS长度的复杂度仅为O(1)。

杜绝缓冲区溢出

        因为C字符串的长度和底层数组的长度之间存在着这种关联性,所以每次增长或者缩短一个C字符串,程序都总要对保存这个C字符串的数组进行一次内存重分配操作:

  • 如果程序执行的是增长字符串的操作,比如拼接操作,那么在执行这个操作之前,程序需要先通过内存重分配来扩展底层数组的空间大小——如果忘了这一步就会产生缓冲区溢出
  • 如果程序执行的是缩短字符串的操作,比如截断操作,那么在执行这个操作之后,程序需要通过内存重分配来释放字符串不再使用的那部分空间——如果忘了这一步就会产生内存泄漏

与C字符串不同,SDS的空间分配策略完全杜绝了发生缓冲区溢出的可能性:当SDS API需要对SDS进行修改时,API会先检查SDS的空间是否满足修改所需的要求,如果不满足的话,API会自动将SDS的空间扩展至执行修改所需的大小,然后才执行实际的修改操作,所以使用SDS既不需要手动修改SDS的空间大小,也不会出现缓冲区溢出问题。

减少内存重分配次数

        C字符串每次修改都需要重新分配内存,因为内存重分配通常是一个比较耗时的操作:Redis作为数据库,经常被用于速度要求严苛、数据被频繁修改的场合,如果每次修改字符串的长度都需要执行一次内存重分配的话,那么光是执行内存重分配的时间就会占去修改字符串所用时间的一大部分,如果这种修改频繁地发生的话,可能还会对性能造成影响。因此SDS实现了空间预分配和惰性空间释放两种优化策略。

空间预分配

        空间预分配用于优化SDS的字符串增长操作:当SDS的API对一个SDS进行修改,并且需要对SDS进行空间扩展的时候,程序不仅会为SDS分配修改所必须要的空间,还会为SDS分配额外的未使用空间。未使用空间的大小和字符串的大小相等,最大为1MB,即字符串大小大于1MB时,预留1MB的未使用空间。当预留的空间足够字符串的增长需求时,就无需进行空间重分配,通过空间预分配策略,Redis可以减少连续执行字符串增长操作所需的内存重分配次数。

惰性空间释放

        惰性空间释放用于优化SDS的字符串缩短操作:当SDS的API需要缩短SDS保存的字符串时,程序并不立即使用内存重分配来回收缩短后多出来的字节,而是使用free属性将这些字节的数量记录起来,并等待将来使用。SDS也提供了相应的API,让我们可以在有需要时,真正地释放SDS的未使用空间,所以不用担心惰性空间释放策略会造成内存浪费。

二进制安全

        C字符串中的字符必须符合某种编码(比如ASCII),并且除了字符串的末尾之外,字符串里面不能包含空字符,否则最先被程序读入的空字符将被误认为是字符串结尾,这些限制使得C字符串只能保存文本数据,而不能保存像图片、音频、视频、压缩文件这样的二进制数据。为了确保Redis可以适用于各种不同的使用场景,SDS的API都是二进制安全的,所有SDS API都会以处理二进制的方式来处理SDS存放在buf数组里的数据,程序不会对其中的数据做任何限制、过滤、或者假设,数据在写入时是什么样的,它被读取时就是什么样。

总结

        SDS是专门为Redis设计的字符串表示结构,相比于传统C字符串,SDS在动态修改方面具有更优秀的性能,通过空间预分配和惰性空间释放两种优化策略减少内存重分配次数,这是一种空间换时间的思想。自动的内存分配也更加安全,杜绝缓冲区溢出的风险。功能上也比传统C字符串更强大,不仅能保存文本数据还支持二进制数据。

参考

《Redis设计与实现》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2215074.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

助力语音技术发展,景联文科技提供语音数据采集服务

语音数据采集是语音识别技术、语音合成技术以及其他语音相关应用的重要基础。采集高质量的语音数据有助于提高语音识别的准确性,同时也能够促进语音技术的发展。 景联文科技作为专业的数据采集标注公司,支持语音数据采集。可通过手机、专业麦克风阵列、专…

极米智驾仪表盘(开源!!)

1.演示: 驾驶界面图 有图无真相,下面视频展示: 汽车仪表盘展示 整个汽车中控仪表盘界面展示: 极米智驾仪表盘中控 极米智驾仪表盘在arm开发板上运行的效果: (因为CSDN只能上传到2M多的视频大小,所以视频只…

C++笔记之类三种的继承方式

C++笔记之类三种的继承方式 code review! 文章目录 C++笔记之类三种的继承方式1.《C++ Primer Plus》(第6版)中文版Page 5502.C++类继承方式与能否隐式向上转换的关系1.《C++ Primer Plus》(第6版)中文版Page 550 除基类私有成员变量外(基类公有成员变量和保护成员变量):…

Golang | Leetcode Golang题解之第479题最大回文数乘积

题目: 题解: func largestPalindrome(n int) int {if n 1 {return 9}upper : int(math.Pow10(n)) - 1for left : upper; ; left-- { // 枚举回文数的左半部分p : leftfor x : left; x > 0; x / 10 {p p*10 x%10 // 翻转左半部分到其自身末尾&…

【火山引擎】 Chat实践 | 大模型调用实践 | python

目录 一 前期工作 二 Doubao-pro-4k_test实践 一 前期工作 1 已在火山方舟控制台在线推理页面创建了推理接入点 ,接入大语言模型并获取接入点 ID。 2 已参考安装与初始化中的步骤完成 SDK 安装和访问凭证配置

初级网络工程师之从入门到入狱(四)

本文是我在学习过程中记录学习的点点滴滴,目的是为了学完之后巩固一下顺便也和大家分享一下,日后忘记了也可以方便快速的复习。 网络工程师从入门到入狱 前言一、Wlan应用实战1.1、拓扑图详解1.2、LSW11.3、AC11.4、抓包1.5、Tunnel隧道模式解析1.6、AP、…

Golang | Leetcode Golang题解之第473题火柴拼正方形

题目&#xff1a; 题解&#xff1a; func makesquare(matchsticks []int) bool {totalLen : 0for _, l : range matchsticks {totalLen l}if totalLen%4 ! 0 {return false}tLen : totalLen / 4dp : make([]int, 1<<len(matchsticks))for i : 1; i < len(dp); i {dp…

pymobiledevice3使用介绍(安装、常用命令、访问iOS沙盒目录)

项目地址&#xff1a;https://github.com/doronz88/pymobiledevice3 首先先介绍一下pymobiledevice3&#xff0c; pymobiledevice3是用Python3 实现的&#xff0c;用于处理 iDevices&#xff08;iPhone 等&#xff09;。它可以跨平台使用&#xff0c;支持&#xff1a;windows…

如何启动hive

检查mysql是否启动 通过Navicat测试mysql是否可以连接 找打hive配置文件所在目录 检查连接mysql的账号密码是否正确,如果不正确就要修改为正确的 初始化hive元数据存储的库:schematool -dbType <database_type> -initSchema 检查mysql中是否创建hive数据库,这里看到hive数…

Windows11远程桌面连接的详细步骤

1、打开设置 2、关闭被控电脑的防火墙 设置中搜索“防火墙” 关闭防火墙 最好三个防火墙都关上 3、打开被控电脑的远程桌面允许 设置中搜索“远程桌面” 打开远程桌面 4、查询电脑输入IP地址 Windows键R键打开CMD&#xff0c;输入ipconfig查询IP地址 5、查询电脑用户名 设置…

入门CCRC数据安全评估师认证要学习哪些内容?

CCRC-DSA&#xff08;中国网络安全审查认证和市场监管大数据中心-数据安全评估师&#xff09;认证&#xff0c;作为国内数据安全领域的权威认证之一&#xff0c;对于从事数据安全工作的专业人士来说&#xff0c;具有极高的含金量。 那么&#xff0c;想要考取这一认证&#xff…

鸿蒙开发 四十一 ArkTs 模块化实战

实际开发中&#xff0c;可能有些工具类或者一些公共代码&#xff0c;用的地方比较多&#xff0c;这时候就可以封装成一个模块 在tools目录下新建了一个module1.ets文件&#xff0c;定义了一个变量name1&#xff0c;定义好之后&#xff0c;另外起一行用export default 修饰name…

面对配分函数 - 随机最大似然和对比散度篇

序言 在统计学和机器学习的领域中&#xff0c;随机最大似然&#xff08; Stochastic Maximum Likelihood \text{Stochastic Maximum Likelihood} Stochastic Maximum Likelihood&#xff09;和对比散度&#xff08; Contrastive Divergence \text{Contrastive Divergence} Con…

使用docker部署Sentinel

Sentinel 是一个由 Redis 开发的高可用性解决方案&#xff0c;主要用于监控和管理 Redis 集群中的节点。其主要功能包括&#xff1a; 监控&#xff1a;Sentinel 监控 Redis 集群中的各个节点的状态&#xff0c;包括主节点、从节点和 Sentinel 自身的状态。它会定期检查节点是否…

Video-LLaMA论文解读和项目部署教程

Video-LLaMA: An Instruction-tuned Audio-Visual Language Model for Video Understanding 相关工作 大型语言模型: 本文的工作基于这些LLM,并提供即插即用插件,使其能够理解视频中的视觉和听觉内容。 多模态大型语言模型: 现有的方法可以分为两大类。 第一类包括使用LL…

Flutter 获取手机传感器数据

前言 在Flutter中可以使用sensors_plus插件来访问加速度计、陀螺仪、磁力计以及气压传感器 sensors_plue的平台支持 平台 是否支持 Android✅iOS✅MacOS❌Web✅Linux❌Windows❌ sensors_plue的要求 Flutter >3.19.0Dart >3.3.0 <4.0.0iOS >12.0MacOS >10.…

Mac 编译 Unreal 源码版本

Mac M3 Pro、XCode 16.0、Unreal 5.4 分享下我本地操作的全流程和遇到的问题 安装 XCodeGithubDesktop 克隆自己 Fork 的仓库运行 Setup.command运行 GenerateProjectFiles.command 出现警告&#xff1a;Platform Mac is not a valid platform to build. Check that the SDK i…

【C】分支与循环1----if与switch

分支与循环 C语言是一门结构化的程序设计语言 顺序结构选择结构循环结构 if语句 if if 语句的语法形式如下: if(表达式)语句表达式成立(为真)&#xff0c;则语句执行&#xff0c;表达式不成立(为假)&#xff0c;则语句不执行 在C语言中&#xff0c;0为假&#xff0c;非0表…

【React】使用脚手架或Vite包两种方式创建react项目

1.使用脚手架搭建React项目&#xff1a; 在终端窗口运行如下命令即可&#xff1a; npx create-react-app react-basic(创建的文件目录) npx&#xff1a;Node.js工具命令&#xff0c;用于查找并执行后续的包命令。 2.使用Vite包创建React项目&#xff1a; 在终端窗口运行如…

Jetpack-Room

Room是Android Jetpack中的一个组件&#xff0c;它提供了一个抽象层&#xff0c;帮助开发者在本地数据库&#xff08;如SQLite&#xff09;上进行持久化数据存储。Room通过简化数据库操作&#xff0c;使得数据管理变得更加容易和高效。 Room重要的概念 实体&#xff08;Entit…