除仅用于字符串字面量的情况外,对于可以被修改值的字符串的表示,Redis底层并没有采用C语言传统的字符串表示,即以空字符结尾的字符数组,而是采用专门为其设计的简单动态字符串作为其默认字符串表示,其英文全称为Simple Dynamic String,简称SDS。除了用于保存数据库中字符串值外,SDS也可以用于缓冲区buffer,比如AOF中的缓冲区、客户端输入缓冲区等。本文,我们将详细研究简单动态字符串SDS的实现及其在性能等方面的独特之处。

注:内容总结于《Redis设计与实现》一书!

SDS实现

SDS整体结构如下:

struct sdshdr {// buf数组中已使用字节数量,即SDS所保存的字符串长度int len;// bur数组中未使用字节数量int free;// 用于保存字符串的字节数组char buf[];
}

可以看到,SDS依然依靠字节数组char buf[]来保存字符串,但是,它还保存了字节数组char buf[]中已使用和未使用字节数量len、free,而len的含义即SDS所保存的字符串长度,free的含义则是SDS剩余可以容纳字符串的长度。一个简单的示例如下:

上图所示的SDS,存储了字符串"Redis",其长度为5,同时尚有4个字节的空间未被利用。而且,你会发现,其实buf数组的大小实际为10,在字符串末尾还有一个表示空字符的'\0',为什么会这样呢?这就是SDS设计的巧妙之处,它为了能够直接重用C字符串函数库里的一些字符串常用函数,而这个空字符是SDS自动添加的,且不计算在len和free内,对用户而言是透明的。

SDS较C字符串的优点

SDS为什么要做以上设计呢,它对于C字符串而言,有哪些优点?

其相比较于C字符串的优点总结如下:

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

C字符串并不会记录字符串的长度,必须遍历整个字符串,对遇到的每个非空字符计数,直到遇到代表字符串结尾的空字符,才能计算出字符串长度,其时间复杂度为O(N),而SDS则直接获取len属性值即可获知字符串长度,其时间复杂度为O(1),而len属性是SDS相关函数自动完成的,对于用户而言是透明的。这个优点对任何一个,即使非常长的字符串反复执行STRLEN命令,也不会对系统性能产生影响,确保了获取字符串长度不会成为Redis的性能瓶颈。

2、杜绝缓冲区溢出

当修改或替换C字符串中的值时,C字符串由于不会记录本身长度,也不会预分配空间,会产生缓冲区溢出,甚至偷偷修改其他字符串内容的情况,如下图所示:

如果我们想在S1现有字符串基础上追加一个Cluster,而又不对S1进行内存重分配,那么这个操作会造成缓冲区溢出,同时会偷偷修改掉S2字符串的值。而SDS的空间分配策略则会避免缓冲区溢出的情况发生,它会先检查len和free,确保要追加、修改、替换的长度能够得到满足,如不满足,则会自动进行空间再分配,从而避免缓冲区溢出。

3、减少字符串修改内存重分配次数

显然,Redis是使用场景决定了存储于其内的字符串会频繁的被修改,而如果是在C字符串情况下,就会发生以下两种情况:

3.1、对于增长性字符串修改操作,程序每次都需要通过内存重分配来满足字符串空间要求,如果忘了,则会产生2中所说的缓冲区溢出;

3.2、对于缩短性字符串修改操作,程序需要通过内存重分配来释放不再使用的空间,如果忘了,则会产生内存泄露的问题。

而内存重分配算法比较复杂,且涉及到系统调用,通常是一种比较耗时的操作,而SDS则依靠空间预分配和惰性空间释放两种策略解决了上述两个问题,减少了频繁的空间重分配等,提供了系统性能。总结如下:

(1)空间预分配

如果SDS修改后,其长度小于1M,也就是len小于1M,则程序会分配与len属性同样大小的未使用空间,即len=free,buf实际大小则还要加1,因为有上述兼容C字符串库函数所使用的空字符;如果SDS修改后其长度大于等于1M,则程序每次会分配1M的未使用空间,此时free等于1M,buf实际大小也是还要加,原因同上。

(2)惰性空间释放

如果SDS字符串被缩短,未使用字节数增大,则SDS并不会使用内存重分配立即回收缩短后的未使用空间,而是记录在free属性中,等待将来使用,这样,惰性空间释放策略避免了SDS缩短字符串时所必须的内存重分配回收空间操作,为将来可能的增长操作使用,提高了Redis字符串处理的性能。同时,对于真正需要释放空间的情况,SDS则提供了专门的API,供用户使用,避免空间的持续浪费。

4、二进制安全

C字符串以空字符作为字符串结尾的特点,决定了其只能保存文本数据,而不能存储图片、视频、音频等二进制数据,而SDS通过len属性则避免了这一情况,使其可以存储诸如上述图片、视频、音频等任意格式的二进制数据。

5、兼容部分C字符串函数

buf中末尾自动追加的空字符实现了SDS可以兼容部分C字符串函数,比如对比strcasecmp、追加strcat等函数。

SDS与C字符串对比如下:

SDS简单总结如下:

《Redis设计与实现》阅读:Redis底层研究之简单动态字符串SDS相关推荐

  1. Redis源码阅读笔记(1)——简单动态字符串sds实现原理

    首先,sds即simple dynamic string,redis实现这个的时候使用了一个技巧,并且C99将其收录为标准,即柔性数组成员(flexible array member),参考资料见这里 ...

  2. 【redis源码学习】simple dynamic strings(简单动态字符串 sds)

    文章目录 接 化 sds 结构分析 基本操作 创建字符串 释放字符串 sdsMakeRoomFor 扩容 小tip:`__attribute__ ((__packed__))` 发 接 阅读源码之前, ...

  3. Redis源码初探(1)简单动态字符串SDS

    前言 现在面试可太卷了,Redis基本是必问的知识点,为了在秋招中卷过其他人(虽然我未必参加秋招),本菜鸡决定从源码层面再次学习Redis,不过鉴于本菜鸡水平有限,且没有c语言基础,本文不会对源码过于 ...

  4. Redis内部数据结构详解之简单动态字符串(sds)

    本文所引用的源码全部来自Redis2.8.2版本. Redis中简单动态字符串sds数据结构与API相关文件是:sds.h, sds.c. 转载请注明,本文出自:http://blog.csdn.ne ...

  5. 《Redis设计与实现》阅读笔记(二)--简单动态字符串

    简单动态字符串 Redis只在一些无需对字符串进行修改的地方使用C字符串,大部分时候使用简单动态字符串(simple dynamic string, SDS),字符串的抽象类型.二进制安全,可以存放任 ...

  6. Redis数据结构之简单动态字符串SDS

    Redis的底层数据结构非常多,其中包括SDS.ZipList.SkipList.LinkedList.HashTable.Intset等.如果你对Redis的理解还只停留在get.set的水平的话, ...

  7. Redis数据结构——简单动态字符串-SDS

    1.SDS简介: redis没有使用C语言传统的字符串表示(以空字符结尾的字符数组),而是自己构建了一种名为简单动态字符串(SDS)的抽象类型,并将SDS用作redis的默认字符串表示. 除了用来保存 ...

  8. Redis之简单动态字符串sds

    转载:https://segmentfault.com/a/1190000012262739 redis在处理字符串的时候没有直接使用以'\0'结尾的C语言字符串,而是封装了一下C语言字符串并命名为s ...

  9. Redis源码剖析(十)简单动态字符串sds

    在对象系统概述中发现,好像所有和字符串有关的内容都有sds的存在,实际上,它是Redis内部对于c字符串的封装,所谓c字符串,其实就是char *,在sds.h头文件中可以清楚的看到它的定义 //sd ...

  10. redis笔记_源码_简单动态字符串SDS

    参照:https://zcheng.ren/sourcecodeanalysis/theannotatedredissourcesds/#sds%E5%B0%8F%E7%BB%93 这里用char b ...

最新文章

  1. MySQL-MHA集群部署(binlog复制)
  2. spring @Order注解
  3. 《算法竞赛入门经典》 例题3-5 生成元 (Digit Generator, ACM ICPC Seoul 2005,UVa)
  4. MOV及MP4文件格式中几个重要的Table
  5. Ajax基于rest风格上传图片
  6. 服务器好玩的项目_GitHub 上有什么好玩的项目?(附地址)
  7. n1盒子当无线打印服务器,n1下ubuntu安装cups配置airprint网络打印服务器
  8. 【PHP编程】制作表单生成器——注册登录信息
  9. camera一些常见名词缩写
  10. oracle卸载步骤图解,Oracle完全卸载步骤
  11. 这些年我要读的书【不断更新中】
  12. mfc函数---CFileDialog的用法
  13. git 移除项目版本控制_Git - 关于版本控制
  14. flask装饰器顺序
  15. 中国制霸生成器火了/ 马斯克香水被炒至原价10倍/ 闽南话翻英语算法来了… 今日更多新鲜事在此...
  16. java改成字体_更改JRE字体配置
  17. java实现打印机打印发票路径
  18. 云计算 码率适配限速_一种基于云计算的应用于用户终端的测速方法
  19. 单通道驱动LVDS驱动1080P液晶屏
  20. PHP 开发经验教训

热门文章

  1. 司守奎《数学建模算法与应用》 第二版
  2. 2023考研王道数据结构知识梳理
  3. 任我行打印服务器显示,任我行终极打印
  4. 驾考维语版本-维语驾考手机电脑版-民语驾考网
  5. java 104规约_电网104规约解包(java)
  6. 一看就懂-grep命令详解
  7. json数组转java集合
  8. Python批量查询恶意地址信息
  9. JDK1.8 中文开发帮助文档
  10. html制作跑马灯,html跑马灯制作