Redis 5 种数据结构之 key-value(字符串)

字符串类型是redis的五种基础数据类型之一, 但是Redis字符串类型不是普通的字符串类型,Redis的字符串类型被称为SDS(simple dynamic string)即简单动态字符串,Redis实现了这种抽象数据结构。

在Redis中,当需要的不是字符串常量类型,而是可以修改的字符串时,就会使用SDS. 比如 Redis中包含字符串值的 key-value 对 都是通过SDS实现的。 C字符串在 Redis中经常被用在字符串不被修改的地方,如打印的日志中。

SDS除了保存常用字符串信息(如用户的信息可以被序列化为json字符串 然后存到SDS中,用的时候可以取出来再反序列化)还可以被用作缓冲区, 比如AOF中的AOF缓冲区,客户端输入状态中的输入缓冲区。

举个🌰:

redis > set msg "hello world"
OK


注意这条命令 redis会创建 值为“msg”的 sds对象作为该键值对的key
同时会创建一个值为“world”的 sds对象作为该键值对的value

不单单 只有在value为sds对象时 才会给value用上sds对象
当value 类型为List类型时,List如果存储了字符串 那么该字符串也为 sds对象

sds的底层实现: sds的底层实现类似于 java 中的ArrayList的实现,redis 给sds 分配了有着冗余容量的字符串数据,这样可以减少字符串的再分配当修改字符串时(但是浪费了的空间)

redis sds的实现


struct sdshdr{

    int len #记录当前字符串容量
    int free #记录buf中没有使用的 容量
    char buf[]  #用于保存字符串的值

}

buf最后一个字节保存为空字符‘\0’ 是为了一些函数进行调试同时兼容C语言的一些原生API,例如字符串打印换行的函数。

SDS和C字符串的区别:

1.  C字符串获取字符串长度信息的时间复杂度时O(N)的时间复杂度,需要遍历自负数组完成,但是SDS在Redis的数据结构中保存了len属性,所以获取字符串长度的时间复杂度是O(1)

2. 防止内存溢出,C字符串在进行字符串拼接的时候,需要显式的调用C语言库函数 入malloc函数,然后进行字符串拼接, 如果分配的内存不够的话那么字符串拼接会造成内存溢出, 但是Redis的字符串进行拼接的时候,会先判断sds里面的buf空间够不够存,如果不够存再进行扩容,然后进行字符串修改,避免了缓冲区溢出。

3. Redis的字符串通过流出冗余空间减少了字符串修改时,内存重新分配次数。

 3.1 需要给字符串 append 字符时如果 字符数组空间够就直接append 到数组后,如果不够再进行扩容,但是c字符串每一次都需要扩容,重新分配空间

3.2 当字符串缩减到时候,c字符串需要重新分配内存,使内存大小达到缩减后到大小,但是Redis的sds在字符串缩减的时候并不会立刻释放空间,采用了惰性释放策略,Redis会通过改变 SDS中len的大小来表示释放空间,真实空间并没有被free掉,这样可以在以后进行复用,从而减少了内存分配次数。SDS的api提供了主动释放惰性空间的方法,从而避免内存溢出。

SDS的内存分配策略:

当对 sds进行修改后,如果sds 对大小 小于在 1M 那么内存的的扩容每次都是len乘2,如果大于1M每次扩容会扩容1M。

另外:redis 中的字符串分为 embeded 和 raw两种, 其中当字符串 超过44字节的时候使用row储存,当小于44字节的时候使用embeded的形式储存, embeded和raw的区分在redisObject对象上的encoding属性上区分同时这个熟悉指明了下面ptr这个属性会指向哪种数据结构(Redis 的每种数据结构都可以基于不同的底层数据结构来实现)但是的底层数据结构会在一定的情况下切换,比如上面说的当字符串sds对象当储存的字符串长度小于44字节使用embeded 而大于44使用raw形式,这个是因为使用c语言使用malloc函数分配内存会分配固定大小的内存(如 32字节64字节)如果要存的字符串小于44那么这个字符串的长度加字符串头的长度会刚好小于64字节(如果分配64字节的话)这样就可以减少一次内存的分配次数和回收次数。raw模式相对embeded会多分配一次内存因为 连着字符串头的那部分存储的那部分存储不下这部分字符串。所以超过44字节的字符串Redis会使用raw模式存储。

 

 

参考来自:

Redis设计与实现

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值