2.2 Redis中SDS(简单动态字符串) 与C字符串的区别

引言:

根据传统,C语言使用长度N+1的字符数组来表示长度为N的字符串,并且字符数组的最后一个元素总是空字符’\0’。
例如,图2-3 就展示了一个值为"Redis"的C字符串。
C语言使用这种简单的字符串表示方式,并不能满足Redis对字符串在安全性、效率以及功能方面的要求,接下来的内容将详细对比C字符串和SDS之间的区别,并说明SDS比C字符串更适合用于Redis的原因。

在这里插入图片描述

2.2.1 Redis 可以,以常数复杂度 获取 字符串的长度

在传统的C字符串中,其本身,并不记录字符串的长度信息,如果想获取该字符串的长度,那么就需要对字符串进行遍历,对遇到的每个字符进行计数,知道遇到 0元素或者 字符’\0’,这个操作的复杂度为O(N)。

和C字符串不同的是,Redis 中 SDS 在len 属性中记录了SDS本身的长度,所以获取一个SDS长度的复杂度仅为O(1)。

设置和更新SDS长度的工作,是由SDS的API 在执行时自动完成的,所以使用SDS无需进行任何手动修改长度工作。

通过使用SDS这种字符串结构,Redis 把 获取一个字符串的效率,从O(N) 时间复杂度降低到O(1),即使我们对一个非常长的字符串键,进行反复的执行STRLEN 命令,也不会对系统性能造成任何影响,因为STRLEN命令的时间复杂度仅为O(1)。

2.2.2 杜绝了缓冲区溢出

传统C字符串,除了获取字符串长度以外,还会造成缓冲区溢出的问题。

例如如果 对一个已经分配好内存空间的C语言字符串 char *dest,如果这个时候要对该字符串进行追加的话,那么如果在没有追加之前没有为dest额外分配额外的空间(这往往是粗心的程序猿所做的,但是C语言中确实是这样的。每一次对字符串进行新增或者修改,都要进行一次内存分配),一旦没有提前进行分配,那么就会产生缓冲溢出。

举个例子,加入程序中,有2个在内存中紧邻的C字符串s1和s2,其中s1保存了"redis",
s2保存了 “mysql5.7”,如图2-7所示。

在这里插入图片描述

如果一个程序员,决定通过执行:

strcat(s1," Java");

那么s1的内容将会被修改为"redis JAVA"(10个字符),但是粗心的他却忘了在执行此函数之前,为s1分配足够的内存空间,那么在strcat函数执行之后,s1的数据将会溢出到s2所在的空间中,会导致s2保存的内容以外地被修改,如果2-8所示。

在这里插入图片描述

与C字符串不同的是,SDS 的空间分配策略完全杜绝了发生缓冲区溢出的可能性:当SDS的API需要对SDS进行修改时,API 会先检查SDS 的空间是否满足修改所需的要求,如果不满足的话,API 会自动将SDS 的空间扩展至执行修改所需的大小,然后才执行实际的修改操作问题,所以使用SDS既然不需要手动修改SDS的空间大小,也不会出现前面所说的缓冲区溢出问题。

举个例子,SDS的API里面也有一个用于执行拼接操作的sdscat函数,可以将一个C字符串拼接到给定SDS所保存的字符串的后面,但是在执行拼接操作之前,sdscat会先检查给定SDS的空间是否足够,如果不够的话,sdscat就会先扩展SDS的空间,然后才执行拼接操作。

例如,如果我们执行:

sdscat(s," Cluster");

在这里插入图片描述

其中SDS值s 如图2-9 所示,那么sdscat将在执行拼接操作之前检查s的长度是否足够,在发现s目前的空间不足以拼接" Cluster"之后,sdscat就会扩展s的空间,然后才执行拼接
" Cluster"的操作,拼接操作完成之后的SDS如图2-10所示。
在这里插入图片描述
注意:图2-10所示的SDS,sdscat不仅对这个SDS进行了拼接操作,它还为SDS分配了13字节的未使用空间,并且拼接之后的字符串也正好是13字节长,这种现象既不是bug也不是巧合,它和SDS的空间分配策略有关。

链接: 2.2.3 Redis中的SDS减少修改字符串时带来的内存重分配次数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值