本文你能得到:
1 SDS基本介绍 。
2 SDS与 C语言传统字符串的区别,为什么使用SDS。
3 SDS的结构和策略详解。
1 SDS 是什么?用来做什么?
1.1 Redis没有直接使用C语言传统的字符串表示(以空字符结尾的字符数组),而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类型,并将SDS用作Redis的默认字符串表示。
1.2 在Redis的数据库里面,包含字符串值的键值对在底层都 是由SDS实现的。
2 SDS结构:
2.1类
struct sdshdr {
//记录buf数组中已使用字节的数量
//等于SDS所保存字符串的长度
int len;
//记录buf数组中未使用字节的数量
int free;
//字节数组,用于保存字符串
char buf[];
};
2.2图
2.3 讲解
free 用于存储buf数组 剩余可用空间
len用于存储已用空间
buf 字节数组用于存储内容
2.4 问题
为什么数组最后 '\0' 空结尾?
请看3.1
3 char数组介绍的缺点
3.1 char 介绍
char 数组在 写入时候会分配内存 ,比如写入 Redis 就会分配6个存储空间,如图
这样在char读取的时候,首先会根据 内存指针找到开头的R 然后到 \0 结束,如果么有\0 char就不知道什么时候结束,但为啥SDS也要这样呢,因为能复用string.h等对字符串操作的工具类。
缺点1 缓冲区溢出。
举例当两个char <string.h>/strcat函数可以将src字符串中的内容拼接到dest字符串的末尾:
char *strcat(char *dest, const char *src);
如果dest没有分配足够的内存空间,就会导致超出 dest 内存空间的部分 被写上src的数据,超出的部分可能分配给了其他变量,所以会导致其他变量数据错误,缓冲区溢出。
缺点2 内存泄漏
如果通过函数 删除了char数组中的一些数据,如果么有重新分类空间,会导致内存泄漏,删除的部分将不会被使用。
缺点3 重新分配地址
所以每次操作char都需要重新分配内存空间,来解决字符增加导致的缓冲区溢出,和减少字符串导致的内存泄漏,这样每次分配内存就有很大的成本,不适合redis这么频繁的操作。
缺点4 获取数组长度时间复杂度O(N)
如果要获取字符产股 需要循环每一个字符计数,时间复杂度O(N)) 而 SDS只需要返回len就可以时间复杂度O(1)
总结:
1 如果程序执行的是增长字符串的操作,比如拼接操作(append),那么在执行这个操作之前,程序需要先通过内存重分配来扩展底层数组的空间大小——如果忘了这一步就会产生缓冲区溢出。
2 如果程序执行的是缩短字符串的操作,比如截断操作(trim),那么在执行这个操作之后,程序需要通过内存重分配来释放字符串不再使用的那部分空间——如果忘了这一步就会产生内存泄漏。
4 SDS如何解决内存以上问题
4.1 空间预分配解决缓冲区溢出问题,避免频繁分配内存,代价是多一些有可能不会被使用到的空间浪费。
策略1
如果对SDS进行修改之后,SDS的长度(也即是len属性的值)将小于1MB,那么程序分配和len属性同样大小的未使用空间,这时SDS len属性的值将和free属性的值相同。举个例子,如果进行修改之后,SDS的len将变成13字节,那么程序也会分配13字节的未使用空间,SDS的buf数组的实际长度将变成13+13+1=27字节(额外的一字节用于保存空字符)。
策略 2
如果对SDS进行修改之后,SDS的长度将大于等于1MB,那么程序会分配1MB的未使用空间。举个例子,如果进行修改之后,SDS的len将变成30MB,那么程序会分配1MB的未使用空间,SDS的buf数组的实际长度将为30MB+1MB+1byte。
4.2 惰性空间释放可以解决内存泄漏问题,避免频繁分配内存,缺点也是空间浪费。
惰性空间释放用于优化SDS的字符串缩短操作:当SDS的API需要缩短SDS保存的字符串时,程序并不立即使用内存重分配来回收缩短后多出来的字节,而是使用free属性将这些字节的数量记录起来,并等待将来使用。
5 SDS 二进制安全
例如存了"1234\0123" \0会被读成结束
redis通过len
来表示字符串长度,不会因为中间插入了\0
就返回错误结果。
6 C字符串和SDS之间的区别总结
Redis只会使用C字符串作为字面量,在大多数情况下,Redis使用SDS(Simple DynamicString,简单动态字符串)作为字符串表示。
比起C字符串,SDS具有以下优点:
1)常数复杂度获取字符串长度。
2)杜绝缓冲区溢出。
3)减少修改字符串长度时所需的内存重分配次数。
4)二进制安全。
5)兼容部分C字符串函数。
---chenchen