Redis-简单动态字符串

简介

简单动态字符串(Simple Dynamic String),简称SDS;用作 Redis 的默认字符串表示。

SDS 的定义

struct sdshdr
{
	// 记录 buf数组中已使用的字节的数量
	// 等于 SD所保存的字符串的长度
	int len;

	// 记录 buf数组中未使用的字节的数量
	int free;

	// 字节数组,不是用于保存字符,而是用它来保存二进制数据(往下看:二进制安全)
	char buf[];
};

示例:redis 中存入一个 Redis 的字符串
SDS的数据结构

  • free:记录redis中没有使用空间的长度;属性值为0,表示这个SDS没有分配任何没有使用的空间。
  • len:记录redis中数据的长度;属性的值是5,表示这个SDS保存了一个五字节长的字符串。
  • buf:记录redis中数据;属性是一个char类型的数组,数组里面保存了字符串的值,并且以’\0’结束。

备注下:SDS 遵循C语言传统字符串表示(简称C字符串)以空字符串结尾的惯例,但是保存空字符串的1字节空间不计算在SDS 的len属性中,并且为空字符串分配额外的1的字节空间,对使用者来说空字符串是透明的;遵循空字符串的惯例是为了重用部分C字符串的函数库中的函数

SDS 与C 字符串的区别

假设 redis 中存储了一个Redis 的字符串

常数复杂度获取字符串长度

C 字符串并不记录自身的长度信息,所以在获取C 字符串的长度时候程序必须便利整个字符串,对每个字符进行计数,直到遇到字符串结尾的空字符串位置,复杂度为O(N)。
SDS 中有个属性字段 len,可直接返回字符串长度,复杂度为O(1)。对于 len 字段的更新,由SDS 底层的API 在执行更新操作的时候自动完成的。

避免缓冲区溢出

C 字符串并不记录自身的长度带来的另一个问题就是容易导致缓冲区溢出;C 字符串在添加或者更新数据的时候没有额外申请之前刚好的内存就会导致内存溢出。
SDS 在需要进行修改的时候,会优先检查SDS的空间是否满足修改所需的要求,若不满足则自动将SDS的空间扩展到执行修改的所需的大小然后再执行修改操作。

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

C 字符串并不记录自身的长度,所以C 字符串的长度和底层数组的长度之间存在着关联,每次增长或缩短字符都要进行内存重新分配;若是增长字符串,那么程序需要优先内存重分配来扩展底层数组的空间的大小,不然就是导致缓冲区溢出;若是缩短字符串的操作,那么在执行这个操作之后通过内存重分配来释放字符串不再使用那部分空间,不然导致内存泄漏
SDS 避免C 字符串的问题,采用了 预分配惰性空间释放 两种策略:

预分配

SDS 对字符串新增并且需要对SDS空间进行扩展的时候,SDS 底层的API 不仅会分配新的所需空间,并且会分配额外的未使用空间(对SDS 进行修改后,len的长度小于1MB,则API 会给free分配和len 一样的空间大小;若 SDS 长度大于等于 1MB,那么API 会分配1MB 的未使用空间)

惰性空间

SDS 对字符串进行缩短的时候,API并不立即宗信分配多端后的字节空间,二十记录到free 属性中;再有需要的时候进行内存释放

二进制安全

C 字符串除了字符串末尾之外不能包含空字符,否则就会被程序误以为是字符串结尾,从而导致了C字符串只能存储文本
SDS 的API都是二进制安全的,都会以处理二进制的方式来处理SDS存放在buf 数组里面的数据,程序不会对其中的数据做任何的限制、过滤或者假设;这就是 SDS 的属性 buf 是字节数组的原因。

兼容部分C 字符串函数

这里不说明了

图表总结

在这里插入图片描述

常用的API

函数作用时间复杂度
sdsnew创建一个包含C字符串的SDSO(N),N为给定的C字符串的长度
sdsempty创建一个不包含任何内容的空SDSO(1)
sdsfree释放给定的SDSO(N),N为被释放的SDS的长度
sdslen返回SDS的已经使用空间字节数O(1),通过读取对象的len 属性获取
sdsavail返回SDS未使用的空间字节数O(1),通过读取对象的free 属性获取
sdsdup创建一个SDS的副本O(N),N为给定的SDS的长度
stdclear清空SDS保存的字符串内容O(1),由于惰性空间释放策略,只改变了对象的len值
stscat将给定C字符串拼接都SDS字符串的末尾O(N),N为被拼接的C字符串的长度
sdscatsds将给定的SDS拼接到另一个SDS字符串的末尾O(N),N为被拼接的SDS字符串的长度
sdscpy将给定的C字符串复制到SDS里面,覆盖原有的字符串O(N),N为被复制的C字符串的长度
sdsgrowzero保留SDS给定区间的数据,不再全进的数据会被覆盖或者是清除O(N),N为扩展新增的字节数
sdssrange保留SDS给定区间的数据,不再全进的数据会被覆盖或者是清除O(N),N为被保留数据的字节数
sdstrin接受一个SDS和一个C字符串作为参数,从SDS左右两端移除所有在C字符串中出现过的字符串O(M*N),M为SDS的长度,N为给定C字符串的长度
sdscmp对比两个SDS字符串是否相同O(N),N为两个SDS中较短的那个SDS的长度
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值