为了最快的存数据,Redis自定义了一种叫SDS的字符串

前言

Redis是c语言开发,但在Redis中存储字符时却并未使用c字符串,而是自定义了一种字符串类型,叫做简单动态字符串(simple dynamic string, SDS)。之所以要“多此一举”,主要原因在于Redis面对的是大量存取的应用场景,且对速度往往较为严苛。

定义

  1. c语言的字符串就是用N+1个字符数组来存取数据,最后一个元素是空字符’\0’,如下所示:

    image-20210304183639717
  2. 而Redis中的SDS则在此基础上定义了一个数据结构,主要由三部分构成

    • 未使用空间的数量free
    • 已使用空间的数量len
    • char类型的数组(最后一个字节也是保存的空字符’\0’)
image-20210304183726974

下面来讲讲为啥Redis要这样定义她的字符串。

SDS的好处

获取字符串长度时速度更快

  • 这个好理解,c语言里没有存字符串的长度,所以在获取字符串的长度时必须遍历整个字符串

  • 而SDS里存了字符串的长度,直接获取就行了

避免缓冲区溢出

假设有两个字符串,name=“zhangsan”,action=“eat”。当要将action拼接到name后面时,c语言与SDS的处理方式如下

  • c语言中字符串没有记录自身长度,若name中剩余长度小于action的长度,则很有可能造成缓冲区溢出

  • 而SDS在对字符串进行修改之前,会先检查free的长度是否能满足,若太小则自动扩展到足够的大小,这样就

    杜绝了发生缓冲区溢出的可能性

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

c语言在每次进行字符串修改(增长或缩短)操作时,必定会对内存进行重新分配。而在这一过程中有可能会产生以下两个问题:

  • 缓冲区溢出。在增长字符串时若没有对字符串进行内存重分配,则空间会不够用。
  • 内存泄漏。在缩短字符串时没有进行内存重分配以回收多余空间

而SDS则可以减少内存重分配的次数,主要有以下两种方式:

空间预分配
  • 这个就是在增长字符串时除了分配它所需要的长度空间之处,还多分配一点给它。

  • 比如说将action="eat"添加到name="zhangsan"后面,分配给name的空间由原来的11个字节变为6 + 6 + 11,

    总共23字节。(第一个6是action的长度,11是name的长度,另一个6则是多分配的空间)

    下次要增长的时候,如果长度小于action的长度,则不需要执行空间预分配了。

惰性空间释放
  • 惰性空间释放的意思就是在缩短字符串时不会立即释放空间,而是留着,并把长度加给free这个属性。

  • 等到下次要增长的时候直接用就可以了。

无论是空间预分配还是惰性空间释放,都是以一点点”内存浪费“的代价来换取保存的速度增长。

二进制安全

  • c语言使用空字符’\0’来标识字符串是否结束。这样的话要是存二进制的数据有可能会被截断,

    所以c语言不能用来存二进制数据

  • 而SDS是用len属性来标识字符串是否结束的,所以SDS可以存二进制的数据

兼容部分c字符串函数

SDS里的buf数组最后也是用空字符串’\0’来结尾的,这样就能使用一部分c字符串的函数了。

总结

Redis要的是速度,设计SDS这种数据结构的主要目的就是提高存取速度。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值