Redis之简单动态字符串SDS

简单动态字符串SDS

1、什么是SDS?

Redis没有直接使用C语言的传统字符串,而是构建了一种简单动态字符串(Simple dynamic string, SDS)的抽象类型,Redis中的字符串底层都是使用SDS结构进行存储,比如包含字符串的键值对底层都是使用SDS结构实现的。

比如:set msg "hello redis" 向redis中插入一条字符串对象。键和值都是字符串。键msg对象的底层实现是一个保存着字符串msg的SDS。值hello redis对象的底层实现也是一个保存着字符串hello redis的SDS

SDS不仅用来保存字符串值,SDS还在缓冲区中有重要的作用:AOF缓冲区,客户端的输入缓冲区底层实现都是使用SDS

SDS结构定义在sds.h中

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

最后一个字节保存了空字符'\0',保留了C字符串的规范,使得SDS结构的字符串,可以重用一部分C函数库的函数。

2、为什么redis定制了SDS结构,而不使用C字符串呢?

主要是因为C字符串有以下缺点:

  • 获取字符串长度时间复杂度为O(N):C字符串获取长度需遍历整个字符串,遇到'\0'空字符为止。

  • 缓冲区溢出:比如在进行字符串追加操作时,如果没有分配足够的内存,就会造成内存溢出。

  • 内存重分配:每次增长或者截短字符串,程序都要对保存C字符串的数组进行内存重分配操作,而内存重分配涉及复杂的算法,并可能需要执行系统调用,所以它通常比较耗时。

  • 空字符问题:C字符串中间不能保存空格,否则程序遍历是会误认为是字符串的末尾。这一限制导致C字符串只能存储文本数据,不能保存像图片、音视频、压缩文件等二进制数据。

3、SDS是通过怎样的设计解决C字符串的问题呢?

1、SDS通过len属性记录了SDS长度,所以获取长度的时间复杂度为O(1),即strlen命令的时间复杂度是O(1)

2、SDS空间分配策略避免了缓冲区溢出:当对SDS进行修改时,会先检查SDS空间是否满足修改,不满足会自动扩展到所需大小,然后才执行修改。

3、较少修改字符串时内存重分配次数:SDS中的free记录buf字节数组中未使用的字节。redis通过free属性实现空间预分配、惰性空间释放两种优化策略。

  • 空间预分配:当对SDS进行增长操作时,程序不仅会分配修改所必须得空间,还会为SDS分配额外的未使用空间。通过预分配策略,减少了连续执行字符串增长操作时内存重分配次数。

  • 惰性空间释放:当对SDS进行截短操作时,程序并不会立即回收缩短后多出来的字节所占用的内存,而是使用free属性记录多出来的字节数,以供将来使用。如果将来要对这个SDS进行增长操作,未使用空间可能就派上用场,并且增长操作也不一定会执行内存重分配。

4、SDS结构中的buf字节数组,是二进制安全的,不仅可以保存字符,也可以保存二进制数据。

5、SDS保留了C字符串的惯例,将数据的末尾设置为空字符'\0',SDS中之所以保留这一规范是可以重用C字符串函数库的一部分函数,例如追加字符串。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涛声依旧叭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值