Redis数据结构——简单动态字符串

Redis没有直接使用C语言传统的字符串表示,而是构建了一种名为简单动态字符串(SDS)的抽象类型,将其作为Redis的默认字符串表示。在Redis中,C字符串只作为字符串字面量用在无需对字符串进行修改的地方,当Redis需要一个可被修改的字符串时,会使用SDS表示字符串值。

1.SDS数据结构

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

 SDS遵循C字符串以空字符结尾的惯例,其空间不计算在len属性里,会为空字符额外分配空间,并自动添加到字符串末尾。沿用该惯例使得SDS可直接使用一部分C字符串函数库里的函数。

2.SDS的优势

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

C字符串本身不存储字符串长度,因此要获取字符串长度时需遍历字符串,复杂度为O(N)。

而SDS本身记录了字符串长度,获取字符串长度的复杂度为O(1)。其中SDS设置和更新长度的工作时由SDS的API在执行时自动完成的,无需进行手动修改的操作。

(2)杜绝缓冲区溢出

strcat会假定用户在执行函数时,已经为dest分配了足够的内存足以保存src字符串的内容,当假定不成立时,会发生缓冲区溢出。例如两个字符串在内存中保存的空间相邻,此时需要在对第一个字符串执行strcat操作,此时第一个字符串的空间不足,会导致新增的字符串内容溢出到第二个字符串的空间,而将第二个字符串的内容覆盖。

而需要对SDS进行字符串拼接,会先检查该SDS空间是否足够,若不足够会先进行扩容操作,然后再执行拼接操作。

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

内存重分配通常是个比较耗时的操作,若每次修改字符串长度都要进行一次内存重分配的话,会对Redis性能造成一定影响。

SDS通过未使用空间解除了字符串长度和底层数组长度之间的关系,在数组中可以包括未使用字节,其中free表示未使用字节长度

  1. 空间预分配:用于优化字符串增长操作,当需要对SDS进行扩容时,不仅会分配SDS修改锁必要的空间,还会额外分配未使用空间。若修改后len<1MB,则分配free的长度与len相同;否则分配1MB未使用空间。通过空间预分配可减少由于字符串增长造成的内存重分配操作。
  2. 惰性空间释放:用于优化字符串缩短操作,当需要缩短SDS保存的字符串时,并不会立即回收多出来的字节,而是用free属性把这些字节数量记录下来,以待将来使用。

(4)二进制安全

C字符串中的字符必须符合某种编码,并且除了字符串末尾,字符串里不能包含空字符,因此C字符串只能保存文本数据。

而SDS是通过len而不是空字符判断字符串是否结束,并且程序不会对数组的数据进行任何处理,数据写入时是什么样,读取时就是什么样。SDS不是用这个数组保存字符,而是保存一系列二进制数据,因此SDS是二进制安全的。

(5)兼容部分C字符串函数

由于SDS遵循C字符串以空字符结尾的惯例,因此保存文本的SDS可重用一部分C字符串库里定义的函数。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值