[redis] 数据结构与对象--简单动态字符串SDS
在Redis里,C字符串常常用于无需对字符串值进行修改的地方。需要被修改的字符串使用SDS(简单动态字符串)。此外SDS还被用在AOF缓冲区和客户端状态中的输入缓冲区的实现。
本文学习记录主要包括以下两点:SDS的定义、SDS和C字符串的区别。
一、SDS的定义
struct sdshdr {
// SDS字符串的长度
int len; // 记录buf数组中,已经使用的字节的数量
int free; // 记录buf数组中,未使用的字节的数量
char buf[]; // 字节数组,用于保存字符串
}
初始化时,len=5,free=0,buf数组中存有五个字符r e d i s 和空字符’\0’。空字符’\0’是额外分配1字节的,不计入字符串长度len中。
二、SDS相对于C字符串的优点
总的来说,SDS优于C字符串在如下几个方面:
获取字符串长度的时间复杂度为O(1)
杜绝了缓冲区的溢出
减少了修改字符串时内存重分配的次数
二进制安全
SDS兼容部分C字符串函数
1. SDS只需常数时间复杂度即可获取长度
C字符串获取长度虚呀遍历,遇到空字符’\0’结束。SDS只需要访问len属性即可。设置和更新len属性是SDS的API在执行的时候完成的。
2. 杜绝缓冲区的溢出
这跟SDS的空间分配策略有关(下一节)在C语言中,若两个字符串在内存中紧邻,对前一个字符串进行修改可能会导致后一个字符串被覆盖。
3. 减少了修改字符串时内存重分配的次数
每次对增长或者缩短一个C字符串,程序都要对其数组进行一次内存重分配,不仅消耗资源,还有产生缓冲区溢出或者内存泄漏的风险。SDS通过未使用空间接触了字符串长度与底层数组之间的关联。SDS通过未使用空间实现了两种优化策略:空间预分配、惰性空间释放
(1)空间预分配
修改SDS时,先检查未使用空间是否足够,如果足够,则直接使用;如果不够,则执行以下内存重分配策略。
若SDS修改后,len小于1MB,那么程序分配未使用空间大小free=已使用空间大小len。此时SDS的buf数组实际长度为len + free + 1字节,其中len == free。
若SDS修改后,len大于等于1MB,那么程序分配未使用空间大小free=1MB。此时SDS的buf数组实际长度为len + free + 1字节,其中free = 1MB
(2)惰性空间释放
- 用于优化SDS的缩短操作,当需要缩短字符串时,不是立即重新分配内存来回收空间,而是使用free属性将这些字节的数量记录起来,用于将来使用。
4. 二进制安全
C字符串遇到空字符’\0’就是结束,SDS中有种特殊字符串是以空字符’\0’为分割的。
SDS的所有API都是以处理二进制的方式处理buf数组里的数据,也就是说buf数组里存的是一系列二进制数据(buf数组又称为字节数组)
比如redis-cli进入命令行,set中文字符串后,取出来的是一串16进制字符。而redis-cli —raw进入命令行才能拿到中文。
5. 兼容部分C字符串函数
SDS以空字符’\0’结尾,可以重用
还没有评论,来说两句吧...