Redis数据结构 — SDS

目录

C 语言字符串的缺陷

简单动态字符串SDS

扩容机制

SDS优点


字符串在 Redis 中是很常用的,Key-Value中的Key是字符串类型,Value有时也是字符串类型

Redis 是用 C 语言实现的,但是它没有直接使用 C 语言的 char* 字符数组来实现字符串,而是自己封装了一个名为简单动态字符串(simple dynamic string,SDS) 的数据结构来表示字符串

C 语言字符串的缺陷

在 C 语言里,对字符串操作时,char * 指针只是指向字符数组的起始位置,而字符数组的结尾位置就用“\0”表示,意思是指字符串的结束

  • 若在字符字段中存在“\0”,就会提前结束,造成字符转义
  • 并且,C语言中strlen,获取字符串长度,就是通过字符数组中的每一个字符,并进行计数,当到字符为 “\0” 后,就会停止遍历,未获取正确的字符串长度
  • C 语言标准库中字符串的操作函数是很不安全的,C 语言的字符串是不会记录自身的缓冲区大小的,若后续进行strcat字符串拼接操作,可能就会导致缓冲区溢出。

简单动态字符串SDS

Redis是C语言实现的,其中SDS是一个结构体,源码如下:

  • len,记录了字符串长度。这样获取字符串长度的时候,只需要返回这个成员变量值就行,时间复杂度只需要 O(1)。
  • alloc,分配给字符数组的空间长度。这样在修改字符串的时候,可以通过 alloc - len 计算出剩余的空间大小,可以用来判断空间是否满足修改需求,如果不满足的话,就会自动将 SDS 的空间扩展至执行修改所需的大小,然后才执行实际的修改操作,所以使用 SDS 既不需要手动修改 SDS 的空间大小,也不会出现前面所说的缓冲区溢出的问题。
  • flags,用来表示不同类型的 SDS
  • buf[],字符数组,用来保存实际数据。不仅可以保存字符串,也可以保存二进制数据。

Redis设计通过不同类型的结构体(sdshdr5、sdshdr8、sdshdr16、sdshdr32 和 sdshdr64)选择最适合的数据大小来存储,所以 SDS 设计不同类型的结构体,是为了能灵活保存不同大小的字符串,从而有效节省内存空间。比如,在保存小字符串时,结构头占用空间也比较少。

除了设计不同类型的结构体,Redis 在编程上还使用了专门的编译优化来节省内存空间,即在 struct 声明了 __attribute__ ((packed)) ,它的作用是:告诉编译器取消结构体在编译过程中的优化对齐,按照实际占用字节数进行对齐,即取消内存对齐

扩容机制

SDS 扩容的规则代码如下:

hisds hi_sdsMakeRoomFor(hisds s, size_t addlen)
{
    ... ...
    // s目前的剩余空间已足够,无需扩展,直接返回
    if (avail >= addlen)
        return s;
    //获取目前s的长度
    len = hi_sdslen(s);
    sh = (char *)s - hi_sdsHdrSize(oldtype);
    //扩展之后 s 至少需要的长度
    newlen = (len + addlen);
    //根据新长度,为s分配新空间所需要的大小
    if (newlen < HI_SDS_MAX_PREALLOC)
        //新长度<HI_SDS_MAX_PREALLOC 则分配所需空间*2的空间
        newlen *= 2;
    else
        //否则,分配长度为目前长度+1MB
        newlen += HI_SDS_MAX_PREALLOC;
       ...
}
  • 如果所需的 sds 长度小于 1 MB,那么最后的扩容是按照翻倍扩容来执行的,即 2 倍的newlen
  • 如果所需的 sds 长度超过 1 MB,那么最后的扩容长度应该是 newlen + 1MB,称为内存预分配

内存预分配好处是,下次在操作 SDS 时,如果 SDS 空间够的话,API 就会直接使用 alloc - len表示的剩余可用的空间大小 ,而无须执行内存分配,有效的减少内存分配次数

所以,使用 SDS 即不需要手动修改 SDS 的空间大小,也不会出现缓冲区溢出的问题。

SDS优点

  • 获取字符串长度的时间复杂度为O(1)
  • 支持动态扩容
  • 减少内存分配次数,内存扩容切换在用户态与内核态之间,切换频率过快,造成性能下降
  • 二进制安全,SDS 不需要用 “\0” 字符来标识字符串结尾
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值