Redis的设计与实现 简单动态字符串SDS

191 阅读2分钟

一 SDS的定义

  • Redis没有使用C语言传统的字符串表示,他自己构建了一个简单动态字符串的抽象类型,他就是SDS,redis里面C字符串只会用来无需对字符串进行修改的地方,比如打印日志

  • 数据结构

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

image.png

sds遵循空字符串结尾,因为这样可以直接重用C字符串里面的一些函数比如打印 printf("%s",s->buf)

二 SDS与C字符串的区别

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

    记录自身的长度信息,所以每次获取长度都要遍历,而SDS通过len可以直接得到长度信息,节省性能

  2. 杜绝缓存区溢出

    C语言的字符串不记录自身的长度信息,所以在执行strcat向一个字符串结尾追加另一个字符串时,如果不先扩容,就会把前面的字符串覆盖掉,造成缓存区溢出

  3. 减少修改字符串时带来的内存重分配次数

    C语言的字符串不记录自身的长度信息,增加字符串就要扩容计算,就要重新分配,而SDS通过空间预分配,和惰性空间释放来减少内存重分配

    • 空间预分配

      如果占用空间小于1M,那么就分配和len同样的长度,也就是free空间

    • 惰性空间释放

      当字符串被删除,free空间并不跟着删除,这样下次增加的时候,就可以直接用free的空间

  4. 二进制安全

    C字符串必须符合某种编码,但是有些编码对字符串的判断不一样,比如 redis look,中间有一个空格,对与某个编码可能就是要换行,导致问题,但是SDS判断字符串结束是通过len属性,所以不会有问题。