Redis基础知识(学习笔记11--SDS)
1.SDS介绍(为什么要提出SDS)
无论是Redis的key还是Value,其基础数据类型都是字符串。例如,Hash型Value的field 与 Value的类型、List型、Set型、ZSet型Value的元素都是字符串。虽然Redis是使用标准C语言开发的,但并没有直接使用C语言中传统的字符串表示,而是自定义了一种字符串。这种字符串本身的结构比较简单,但功能却非常强大,称为简单动态字符串,Simple Dynamic String,简称SDS。
注意:Redis中的所有字符串并不都是SDS,也会出现C字符串。C字符串只会出现在字符串“字面常量”中,并且该字符串不可能发生变更。例如,Redis 返回的结果中包含的字符串就是C语言的字符串。
2.SDS结构
SDS 不同于C字符串。C字符串本身是一个以双引号括起来,以空字符串‘\0’结尾的字符串序列。但SDS是一个结构体,定义在Redis安装目录下的 src/sds.h中。
struct sdshdr { //字节数组,用于保存字符串 char buf[]; //buf[]中已使用字节数量,称为SDS的长度 int len; //buf[]中尚未使用的字节数量 int free; }
例如执行 set countey "China" 命令时,键country 与值 ”China“ 都是SDS类型的,只不过一个是SDS的变量,一个是SDS的字面常量,”China“在内存中的结构如下:
通过以上结构可以看出来,SDS的buf值实际上是一个C字符串,包含空字符串‘\0’共占6个字节。但SDS的len是不包含‘\0’的。
在实际的使用过程中,经常会做一些预分配,变成下面这种结构。
该结构与前面不同的是,这里面有3字节未使用空间。
补充
type keyname
可以查看那种类型。
object encoding keyname
可以查看key对应的value在内存中的存储类型。例如,如果返回的是"embstr",就是我们前面说的SDS。
3.SDS的优势
C字符串使用len+1长度的字符串数组来表示实际长度为len的字符串,字符串数组最后以空字符串’\0‘结尾,表示字符串结尾。这种结构简单,但不能满足Redis对字符串功能性、安全性及高效性等的要求。
(1)防止“字符串长度获取”的性能瓶颈
对于C字符串,若要获取其长度,则必须要通过遍历整个字符串才能获取得到。对于超长字符串的遍历,会成为系统的性能瓶颈。而由于SDS结构体中直接就存放着字符串的长度数据,所以对于获取字符串长度需要消耗的系统性能,特别是在长字符串的情况下,不会成为Redis的性能瓶颈。
(2)保障二进制的安全
C字符串中只能包含符合某种编码格式的字符,例如ASCII、UTF-8等,并且除了字符串尾外,其他位置是不能包含空字符串’\0‘的,否则该字符串就会被程序误解为提前结束,而在图片、音频、视频、压缩文件、office 文件等二进制数据中常以空字符串'\0'作为分隔符的情况是很常见的,故而在C字符串中是不能保存图片、音频、视频、压缩文件、office 文件等二进制数据的。
但SDS不是以空字符串'\0'作为结束标志的,其是通过len属性来判断字符串是否结束的。所以,对于程序处理SDS中的字符串数据,无需对数据做任何限制、过滤、假设,只需读取即可。数据写入的是什么,读到的就是什么。
(3)减少内存再分配次数
SDS采用了空间预分配策略与惰性空间释放策略来避免内存再分配问题。
空间预分配策略是指,每次SDS进行空间扩展时,程序不但为其分配所需的空间,还会为其分配额外的未使用空间,以减少内存再分配次数。而额外分配的未使用空间大小取决于空间扩展后SDS的len属性值。
***如果len属性值小于1M,那么分配的未使用空间free的大小与len相同。
***如果len的属性值大于等于1M,那么分配的未使用空间free的大小就是1M。
SDS对于空间释放采用的时惰性空间释放策略。该策略是指,SDS字符串长度如果缩短,那么多出的未使用空间将暂时不释放,而是增加到free中。所以后期扩展SDS时减少内存再次分配。
如果要释放SDS的未使用空间,则可以通过sdsRemoveFreeSpace()函数来释放。
(4)兼容C函数
Redis中提供了很多SDS的API,以方便用户对SDS进行二次开发。为了能够兼容C函数,SDS的底层数组buf[]中的字符串仍以空字符串'\0'结尾。
4 常用的SDS操作函数
函数 | 功能描述 |
sdsnew() | 使用指定的C字符串创建一个SDS |
sdsempty(); | 创建一个不包含任何字符串数据的SDS |
sdsdup(const sds s); | 复制字符串(创建一个指定SDS的副本) |
sdsfree() | 释放指定的SDS |
sdsclear() | 清空指定SDS的字符串内容 |
sdslen() | 获取指定SDS的已使用空间len值 |
sdssaveall() | 获取指定SDS的未使用空间free值 |
sdsMakeRoomFor() | 使指定的SDS的free空间增加指定的大小 |
sdsRemoveFreeSpace() | 释放指定SDS的free空间 |
sdscat() | 将指定的C字符串拼接到指定SDS字符串末尾 |
sdscatsds() | 将指定的SDS的字符串拼接到另一个指定的SDS字符串末尾 |
sdscpy() | 将指定的C字符串赋值到指定的SDS中,覆盖原SDS字符串内容 |
sdsgrowzero(sds s, size_t len); | 扩展SDS字符串到指定长度,这个扩展是使用空字符串’\0‘填充 |
sdsrange(sds s, int start, int end) | 截取指定SDS中指定范围内的字符串 |
sdstrim(sds s, const char *cset); | 在指定SDS中删除所有只当C字符串中出现的所有字符 |
sdsemp() | 对比两个给定SDS字符串是否相同 |
sdstolow() | 将指定SDS字符串中的所有字面变为小写 |
sdstouper() | 将指定SDS字符串中的所有字面变为大写 |
学习参阅声明
【Redis视频从入门到高级】
https://www.bilibili.com/video/BV1U24y1y7jF?p=11&vd_source=0e347fbc6c2b049143afaa5a15abfc1c】
热门相关:攻略初汉 与你相恋的小时光 极品仙师 傲娇小萌妃:殿下太腹黑 司令,以权谋妻