Redis数据结构之SDS

本文介绍了Redis中自定义的简单动态字符串SDS,详细解释了其结构、与C字符串的区别、优化策略以及主要操作API。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SDS

Redis没有直接使用C字符串,而是自己构建了一种简单的动态字符串SDS,并作为Redis的默认字符串。

在Redis中,C字符串只会作为字符串的字面量用在一些无需对字符串修改的地方如打印日志 ,而对于可以被修改的字符串会使用SDS ,
如包含字符串的键值对底层都是用SDS实现的。

例:

redis> SET msg "hello world"
OK

除了用来保存数据库中的字符串值,还被用作缓冲区:AOF模块中的AOF缓冲区,客户端状态中的输入缓冲区。

SDS详解:

SDS定义在源码的 sds.h中的 sdshdr中:

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

图:

这里写图片描述

SDS字符串也以空字符串结尾,保存空字符串的一个字节不计算在SDS的len属性中,
为空字符串分配1个字节并且把它加到字符串末尾的操作由sds函数自动完成。

SDS与C字符串的区别:

C使用N+1个字节来表示长度为N的字符串,并且最后一个元素是空字符’\0’。

  • C字符串无法记录自身的长度,所以想获得长度必须遍历整个字符串。复杂度O(N)。SDS记录了自身的长度,获取长度的复杂度O(1)。

  • C字符串无法记录自身的长度,在做字符串拼接时,容易导致缓冲区溢出。而SDS的API需要对SDS进行修改时会先检查SDS的空间是否满足需求,
    不满足则会自动将SDS的空间扩大,既不要手动修改SDS的大小也不会导致缓冲区溢出。

  • C字符串无法记录自身的长度,包含长度为N的字符串总是使用N+1个字节来实现,每次增长或缩短都需要对内存重新分配,
    内存重分配可能需要执行系统调用,对性能造成影响。SDS通过未使用空间解除了字符串长度和底层数组长度的关联。而且未使用空间使用了
    空间预分配和惰性空间释放两种优化策略。

  • C字符串必须符合某种编码,并且除了字符串末尾外其他地方不可以出现空字符,否则就出现错误,所以C字符串只能保存文本数据,不能是图片、
    音乐等二进制数据。而SDS的API会以处理二进制数据的方式来处理buf中的数据,所以SDS的buf被称为字节数组。

  • SDS遵循C字符串以空字符结尾,所以可以重用C的一部分

优化策略:
  1. 空间预分配
    用于优化SDS字符串增长的操作,当SDS的API对空间做扩展的时候,不仅会为SDS分配必须的空间,还会额外多分配一些。额外分配的空间大小公式
    如下:

    • 若对SDS修改后,SDS大小小于1M,那么会分配长度和len一样的未使用空间,所以len值和free值一样。
    • 若修改后大小大于1M,那么会分配1M
      这样在扩展SDS空间之前,SDS API会先检查未使用空间大小是否足够,若足够就直接使用,不够就执行内存重分配。
  2. 惰性空间释放

    • 用于优化SDS字符串缩短操作,当SDS的API对空间缩短字符串,不会立即对内存重分配来回收缩短后多出来的字节,而是用free属性来将这些
      字节记录起来。
      通过惰性空间释放策略,SDS避免了缩短字符串时所需的内存重分配的操作,并为将来的可能有的增长提供优化。
SDS主要操作API
函数作用时间复杂度
sdsnew创建一个包含C字符串的SDSO(N),N为字符串的长度
sdsempty创建一个不包含任何内容的空SDSO(1)
sdsfree释放给定的SDSO(N),N为释放的SDS的长度
sdslen返回SDS已使用的字节数O(1)
sdsavail返回SDS未使用的字节数O(1)
sdsdup创建一个给定的SDS的副本O(N),N为给定的SDS的长度
sdsclear清空SDS保存的字符串的内容因为惰性空间释放,O(1)
sdscat将给定的C字符串拼接到SDS的末尾O(N),N为C字符串的长度
sdscatsds将给定的SDS字符串拼接到SDS的末尾O(N),N为被拼接的SDS的长度
sdscpy将给定的C字符串复制到SDS里,覆盖SDS原有的字符串O(N),N为被复制C字符串的长度
sdsgrowzero用空字符串将SDS扩展到给定长度O(N),N为新增的字节数
sdsrange保留SDS给定区间内的数据,不在区间内的数据会被覆盖或清除O(N),N为被保留的字节数
sdsrim接受一个SDS和一个C字符串作为参数,从SDS中移出C字符串出现过的字符O(N),N为给定的C字符串的长度
sdscmp对比两个SDS字符串是否相同O(N),N为SDS中较短的那个的长度
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值