当前位置:网站首页>Redis中SDS简单动态字符串
Redis中SDS简单动态字符串
2022-08-09 02:42:00 【FighterLiu】
前言
Redis的底层是使用c语言写的。但是Redis没有直接使用C语言传统的字符串表示(以空字符串结尾的数组,以下简称C字符串),而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的类型,并将SDS用作Redis默认字符串表示。
一、SDS结构
SDS的定义如下:
struct sdshdr{
//记录buf数组中已使用字节的数量
//等于SDS所保存字符串的长度
int len;
//记录buf数组中未使用字节的数量
int free;
//字节数组,用于保存字符串
char buf[];
}
下图展示了SDS示例:
free 属性的值为0,表示这个SDS没有分配任何未使用空间。
len属性的值为5,表示这个SDS保存了一个五字节长的字符串。
buf属性是一个char类型的数组,数组的前5个字节分别保存了‘R’,‘e’,’’d,’i’,’s’五个字符,而最后一个字节则保存了空字符‘\0
SDS遵循C字符串以空字符串结尾的惯例,保存空字符的1字节空间不计算在SDS的len属性里面,并且为空字符分配额外的1字节空间,以及添加空间字符到字符串末尾等操作,都是由SDS函数自动完成的,所以这个空字符对于SDS的使用者来说是完全透明的。遵循空字符结尾这一惯例的好处是,SDS可以直接重用一部分C字符串函数库里面的函数。
二、SDS与C字符串的区别
常数复杂度获取字符串长度
因为C字符串不记录自身的长度信息,所以为了获取一个C字符串的长度,程序必须遍历整个字符串,对遇到的每个字符进行计数,直到遇到代表字符串结尾的空字符为止,这个操作的复杂度未O(N)。在SDS中记录了SDS本身的长度,所以获取一个SDS长度的复杂读仅为O(1).
杜绝缓冲区溢出
C字符串在做字符串内容拼接的时候,需要先分配足够的空间,否则会发生缓冲区溢出。比如下stract函数可以将src字符串的内容拼接到dest字符串的末尾:
char *stract(char *dest,const char *src);
假设程序里有两个在内存中紧邻着的C字符串s1和s2,其中s1保存了字符串“MongoDB”,如图所示
执行如下操作:
strcat(s1,”Cluster”);
在执行这个操作之前,没有给s1分配足够的空间,那么在stract函数之后,s1的数据将溢出到s2所在的空间中,导致s2保存的内容被意外的修改,如下:
与C字符串不同,SDS的空间分配策略完全杜绝了发生缓冲区溢出的可能性:当SDS API需要对SDS进行修改时,API会先检查SDS的空间是否满足修改所需的要求,如果不满足的话,API会自动将SDS的空间扩展至执行修改所需的大小,然后才执行实际的修改操作,所以使用SDS既不需要手动修改SDS空间大小,也不会出现前面所说的缓冲区溢出问题。
减少修改字符串是带来的内存分配次数
在C字符串中每次对其执行增长或缩短操作,程序总要对保存这个C字符串的数组进行一次内存重分配操作。因为内存重分配涉及复杂的算法,并且可能需要执行系统调用,所以它通常是一个比较耗时的操作。对性能也会产生一定的影响。
SDS中有一个free属性记录未使用空间,通过该属性实现了空间的预分配和惰性空间释放两种优化策略。
空间预分配
如果对SDS修改后,SDS长度(也即是len属性的值)将小于1MB,那么程序分配和len属性同样大小的未使用空间,这时SDS len属性的值将和free属性的值相同。例如如果修改之后,SDS的len将变成13字节,那么程序也会分配13字节的未使用空间,SDS的buf数组实际长度将变成13+13+1=27字节(额外的一字节用于保存空字符)。
如果对SDS进行修改之后,SDS的长度将大于等于1MB,那么程序会分配1MB的未使用空间。例如如果修改之后,SDS的len将变成30MB,那么程序会分配1MB的未使用空间,SDS的buf数组的实际场所为30MB+1MB+1Byte。
通过空间预分配策略,Redis可以减少连续执行字符串增长所需要的内存分配次数。因为在扩展SDS空间之前,SDS API会先检查未使用空间是否足够,如果足够的话,API就会直接使用未使用空间,而无需执行内存重分配。
惰性空间释放
惰性空间释放用于优化SDS字符串的缩短操作:当SDS的API需要缩短SDS保存的字符串时,程序并不立即使用内存分配来回收缩短后多出来的字节,而是使用free属性将这些字节的数量记录起来,并等到将来使用。
与此同时,SDS也提供了相应的API,让我们在有需要时,真正地释放SDS的未使用空间,所以不用担心惰性空间释放测试会照成内存浪费。
二进制安全
C字符串中的字符必须符合某种编码(比如ASCII),并且除了字符串的末尾之外,字符串里面不能包含空字符,否则最先被程序读入的空字符将被误认为是字符串结尾,这些限制使的C字符串只能保存文本数据,而不能保存像图片,音频,视频,压缩文件这样的二进制数据。
SDS不会对数据做任何限制,数据在写入时是什么样的,它被读取的时候就是什么样。
边栏推荐
猜你喜欢

SA-SSD环境搭建——血与泪的教训
![[TensorRT] 对UNet进行推理加速](/img/38/fa8ce73a5ae7691d416bf9aaadc769.png)
[TensorRT] 对UNet进行推理加速

Likou Brush Question Record 1.5-----367. Valid perfect squares

online schema change and create index

企业从云服务的承诺支出中获得最大收益的四种方法

高性能 MySQL(十二):分区表

Postman接口测试【官网】最新版本 安装及使用入门教程

HMS Core分析服务智能运营6.5.1版本上线

Working subtotal rtcp length and network byte order

通过安装VNC服务器x11vnc(或vnc4server)和配置x11vnc.service实现远程通过VNC-Viewer访问VNC服务器。
随机推荐
接口自动化测试-接口封装思想
二分搜索法和二叉搜索树
【HNUMSC】C language second lecture
Summary of pytorch related knowledge points
最强分布式锁工具:Redisson
What aspects should we start with for interface security testing?
Programmer's Daily Life | Daily Fun
gpio子系统和pinctrl子系统(中)
数字 05 verilog&vivado2018.2零散笔记
Appium常用操作及H5页面元素定位
第二部分:和查找表相关的问题
php过滤特殊字符(仅保留中文、字母、数字、下划线)
腾讯地图获取定位
VS2019编译boost_1_79,生成32位和64位静态库
自动化测试框架总结
Qt 信号槽connect的同步与异步处理
Jenkins配置钉钉通知
Maya engine modeling
Apache站点下载大文件自动中断或者文件不完整
微信公众号跳转小程序 wx-open-launch-weapp (最全指南及坑)