Redis数据结构实现原理—简单动态字符串

本文详细介绍了Redis中的SimpleDynamicStrings(SDS)数据结构,它与C字符串相比有O(1)的长度获取、避免缓冲区溢出和减少内存重新分配的优势。SDS主要应用于存储键值对、缓冲区和AOF模块。通过空间预分配和惰性空间释放策略,SDS提供了高效且安全的字符串操作。
摘要由CSDN通过智能技术生成

SDS简单动态字符串

  Redis没有直接使用C语言中的字符串,而是自己构建了一个抽象类型,简单动态字符串SDS(Simple Dynamic Strings)。为何没有使用C语言的字符串,来看下两者的区别

C字符串与SDS的区别

C字符串SDS
获取字符串长度复杂度为O(n)获取字符串长度复杂度为O(1)
会出现缓冲区溢出杜绝缓冲区溢出
只能保存文本数据可保存文本和二进制数据
修改字符串长度N次必然需要执行N次内存重新分配修改字符串长度N次最多需要执行N次内存重新分配

SDS用途

  • 存储键值对的键和值
  • 列表对象中的字符串
  • 用作缓冲区(buffer): AOF 模块中的 AOF 缓冲区, 以及客户端状态中的输入缓冲区

SDS数据结构实现

struck sdshdr{
    // 占用空间:用于记录buf数组中使用的字节的数目,和SDS存储的字符串的长度相等  
    unsigned int len;
    // 剩余空间:用于记录buf数组中没有使用的字节的数目   
    unsigned int free;
     //数据空间:用来存储字符串,buf的大小等于len+free+1,其中多余的1个字节是用来存储’\0’的。
    char buf[];
}

SDS的优点

  • 可以直接读取len和free属性来快速获取数据长度和剩余空间,时间复杂度为O(1)
  • 内容存储在动态数组 buf 中,SDS 对上层暴露的指针指向 buf,而不是指向结构体 SDS。因此,上层可 以像读取 C 字符串一样读取 SDS 的内容,兼容 C 语言处理字符串的各种函数,同时也能通过 buf 地址 的偏移,方便地获取其他变量;
  • 读写字符串使用len属性,不像C语言中依赖于 \0,保证二进制安全。
  • 杜绝缓冲区溢出
  • 减少修改字符串时带来的内存重新分配次数

什么机制来减少内存重新分配

  在C语言中,每次对字符串进行增长或缩短时,程序都会进行一次内存重新分配。例如:

  • 字符串拼接操作(append),程序先为增长后的字符串分配内存空间,如果忘记了这一步操作就会产生缓冲区溢出
  • 截断操作(trim)程序需要通过内存重新分配来释放字符串中不再使用的空间,如果忘记了这一步操作就会产生内存泄漏

  为了避免C字符串的这种缺陷,Redis中的SDS通过以下两种策略来优化

空间预分配

用于优化SDS字符串增长操作,扩展前先检查free空间是否够用,足够的话无需分配,不足在进行分配,同时free也会获得同样的len空间

惰性空间释放

用于优化SDS字符串缩短操作,缩短字符串时不会重新分配内存,而是更改free和len和buf,在需要的时候才会真正的释放free多余空间

通过这两种策略实现了修改字符串长度N次必然需要执行N次内存重新分配变成了最多

参考:
《Redis设计与实现》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值