Redis 简单动态字符串底层实现

一、简介

C语言中字符串(一下简称C字符串)的格式是以空字符结尾的字符数组,Redis中没有直接使用C字符串表示,而是自己构建了一种简单动态字符串(Simple Dynamic String, SDS)的数据类型。

SDS的数据结构定义:

struct sdshdr{
	//字符数组,保存SDS的字符串内容
	char buf[];
	//buf[]数组已使用的长度,等于SDS字符串的长度
	int len;
	//buf[]数组中未使用的空间长度
	int free;
};

例如下面这个SDS的例子,它的buf[]数组里保存了"Redis"这个字符串,len为5,free为0。值得注意的是虽然末尾和C字符串一样都有一个空字符表示结尾,但是len长度并不包含这一位。
sds
其实就是在C字符串基础上做了一层封装。那么为什么直接不使用C字符串呢?主要还是处于安全和效率以及功能方面的要求。

二、SDS和C字符串的区别

主要包含以下几点:

(1)常数复杂度获取字符串长度
由于C字符串只是单纯用字符数组保存了字符串内容,所以获取字符串长度时还需要遍历这个字符数组计算长度,时间复杂度是O(n)。而SDS由于引入了len这个属性,所以获取长度的时间复杂度直接变为O(1),对于Redis这种高性能缓存框架来说,效率提升十分明显。

(2)避免缓冲区溢出
C字符串在对其内容进行扩充或者拼接时,需要手动分配足够多的空间,如果忘记分配,那么就会出现缓冲区溢出的问题,也就是原先的空间不够用了。而SDS则解决了这个问题,在需要扩充或者拼接时,会先去判断free中的可用空间够不够,如果不够再去申请足够的空间,这些操作都是Redis来实现的,用户使用的时候是透明的,不需要关注这些底层操作。

(3)减少修改字符串时带来的内存重分配次数

C字符串在执行增长字符串的操作时,都需要程序手动申请更多的空间。在执行缩短字符串的操作时,都需要程序手动释放不再使用的空间。如果忘记申请或者释放空间都会造成问题,但是每次都进行申请和释放操作这种频繁的内存重分配,会直接带来的性能上的问题。在大规模高并发请求下,Redis显然不能接受这种做法。于是SDS采用了空间预分配和惰性空间释放两种优化策略:

  • 空间预分配:也就是某一次SDS中字符串长度需要增长时,不是分配此次需要的空间长度,而是会多分配一些,剩余空闲长度直接修改free字段即可。
  • 惰性空间释放:也就是SDS中字符串内容发生缩减时,不是立即释放空间,而是修改len字段和free字段表示长度发生了减少,可用空间变多了。同时,这样下次字符串内容需要增长时,也就减少了空间分配的操作。

(4)保存二进制内容

C字符串中只能保存文本内容,而SDS中由于引入了len字段,可以保存包含特殊字符的二进制数据内容了。所以其实SDS中的buf[]数组不仅仅是字符数组,也可以称为字节数据。


THE END.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值