【Redis】string简单动态字符串 SDS

SDSSimple Dynamic String,简单动态字符串)是 Redis 底层所使用的字符串表示, 几乎所有的 Redis 模块中都用了 sds。

本文将对 sds 的实现、性能和功能等方面进行介绍

1. redis中的string

先执行几个命令

 可以看到:

  1. 当设置是整数,底层编码则采用int
  2. 当字符串长度小于等于44,底层编码采用embstr
  3. 当字符串长度大于44,底层编码采用raw

digraph {      label = "\n 图 8-1    int 编码的字符串对象";      rankdir = LR;      node [shape = record];      redisObject [label = " redisObject | type \n REDIS_STRING | encoding \n REDIS_ENCODING_INT | <ptr> ptr | ... "];      node [shape = plaintext];      number [label = "10086"]      redisObject:ptr -> number;  }

digraph {      label = "\n 图 8-2    raw 编码的字符串对象";      rankdir = LR;      node [shape = record];      redisObject [label = " redisObject | type \n REDIS_STRING | encoding \n REDIS_ENCODING_RAW | <ptr> ptr | ... "];      sdshdr [label = " <head> sdshdr | free \n 0 | len \n 43 | <buf> buf"];      buf [label = " { 'L' | 'o' | 'n' | 'g' | ... | 'k' | 'i' | 'n' | 'g' | ' ' | '.' | '.' | '.' | '\\0' } " ];      //      redisObject:ptr -> sdshdr:head;     sdshdr:buf -> buf;  }

digraph {      label = "\n 图 8-3    embstr 编码创建的内存块结构";      node [shape = record];      embstr [ label = " { redisObject | { type | encoding | <ptr> ptr | ... } } |  { sdshdr | { free | len | <buf> buf }} " ];  }

embstr 编码是专门用于保存短字符串的一种优化编码方式, 这种编码和 raw 编码一样, 都使用 redisObject 结构和 sdshdr 结构来表示字符串对象,

但 raw 编码会调用两次内存分配函数来分别创建 redisObject 结构和 sdshdr 结构, 而 embstr 编码则通过调用一次内存分配函数来分配一块连续的空间, 空间中依次含 redisObject 和 sdshdr 两个结构。

详细对比参考文章 字符串对象 — Redis 设计与实现

2. 为什么需要sds字符串?

  1. O(1)获取长度,c语言的字符串本身不记录长度,而是通过末尾的\0作为结束标志,而sds本身记录了字符串的长度所以获取直接变为O(1)的时间复杂度、同时,长度的维护操作由sds的本身api实现
  2. 防止缓冲区溢出bufferoverflow:由于c不记录字符串长度,相邻字符串容易发生缓存溢出。sds在进行添加之前会检查长度是否足够,并且不足够会自动根据api扩容
  3. 减少字符串修改的内存分配次数:使用动态扩容的机制,根据字符串的大小选择合适的header类型存储并且根据实际情况动态扩展。
  4. 使用空间预分配和惰性空间释放,其实就是在扩容的时候,根据大小额外扩容2倍或者1M的空间,方面字符串修改的时候进行伸缩
  5. 使用二进制保护,数据的读写不受特殊的限制,写入的时候什么样读取就是什么样
  6. 支持兼容部分的c字符串函数,可以减少部分API的开发

优点:

空间预分配:当一个SDS被修改成更长的buf时,除了会申请本身需要的内存外,还会额外申请一些空间。

惰性空间释放:当一个SDS被修改成更短的buf时,并不会把多余的内存还回去,而是会保存起来。

3. SDS的实现

参考文章 简单动态字符串 — Redis 设计与实现

4. 总结

这种设计的核心思想就是空间换时间,只要free还剩余足够的空间时,下次String变长的时候,不会像系统申请内存。

类似 Python中list的内存管理方式, 本质都是以浪费一些空间为代价,预申请额外的内存,从而减少申请内存的次数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值