美文网首页
Redis底层数据结构SDS

Redis底层数据结构SDS

作者: kyo1992 | 来源:发表于2021-04-06 16:56 被阅读0次

    前言

    Redis是C语言开发的,C语言的字符类型是char,字符数组是char[],Redis没有直接使用C语言的字符串类型,而是在其之上构建动态字符串(SDS)的抽象类型。

    SDS代码

    Redis3.2之前实现方式

    struct sdshdr{
     int len;
     int free;
     char buf[];
    }
    len表示buf数组长度,free表示数组未使用长度。
    而3.2之后扩展为5种类型,主要为了优化len和free这两个字段所占的空间,但实现思想上不变。

    SDS比起C语言字符串优点

    例如存储值为 "haha123"的字符串
    C语言字符串: char data[] = "haha123\0"
    sds:struct{ len: 7, free: 14, buf: "haha123\0" }

    优点1:计数更快
    C语言对字符串长度的统计,就完全来自遍历,从头遍历到末尾,直到发现空字符就停止,时间复杂度为O(n)。
    而sds本身就保存了长度的信息,所以获取长度的时间复杂度为0(1)。

    优点2:杜绝缓冲区溢出
    调用C语言的字符串拼接函数,如果没有提前计算好内存,拼接后会产生缓冲区溢出的。
    如果使用sds,它存储了当前长度len,还有free未使用的长度,做拼接操作,先判断是否可以放得下,如果长度够就直接执行,如果不够,那就进行扩容,再进行拼接。

    优点3:减少修改字符串时带来的内存重分配次数
    当频繁对字符串进行添加时,C语言需要不断开辟新的内存空间以存放新的字符串,频繁内存分配是很耗时的。Redis为了避免C字符串这样的缺陷,就分别采用了两种解决方案,去达到性能最大化,空间利用最大化。

    1. 空间预分配:当我们对SDS进行扩展操作的时候,Redis会为SDS分配好内存,并且根据特定的公式,分配多余的free空间,还有多余的1byte空间(这1byte也是为了存空字符),这样就可以避免我们连续执行字符串添加所带来的内存分配消耗。
      例如新建sds结构存储长度为7的字符串,那么此时len=7,free也是7,当需要拼接一个长度<=7的字符串,就可以例如free的空间直接进行拼接,省去内存重新分配。
      当扩容时,如果需要内存值小于1MB,那么会进行成倍的扩容,如果大于1MB,那么每次扩容增加1M,直到够为止。

    2. 惰性空间释放:刚才提到了会预分配多余的空间,如果一直不需要,可能会带来内存的泄露或者浪费,Redis也做了设计,当执行完一个字符串缩减的操作,Redis并不会马上收回我们的空间,因为可以预防你继续添加的操作,这样可以减少分配空间带来的消耗,但是当你再次操作还是没用到多余空间的时候,Redis也还是会收回对于的空间,防止内存的浪费的。

    优点4:二进制安全
    Redis作为缓存中间件,面向各种客户端通过socket使用,这些客户端数据经常会穿插空字符在中间,比如图片,音频,视频,压缩文件的二进制数据,如果直接使用C语言字符串库去读取,就会造成数据丢失。
    而Redis就不存在这个问题了,因为SDS保存了字符串的长度,他不判断空字符,他就判断长度对不对就好了,所以Redis也经常拿来保存各种二进制数据,例如用来保存小文件的二进制。

    优点5:兼容C语言的函数库
    sds的buf结尾依然会添加'\0'作为结束,这样可以兼容C语言的字符串函数库使用。

    相关文章

      网友评论

          本文标题:Redis底层数据结构SDS

          本文链接:https://www.haomeiwen.com/subject/tzoskltx.html