简单动态字符串:simple dynamic string ,SDS,用作Redis默认字符串表示。
在Redis中,C字符串只会作为字符串字面量用在一些无须对字符串值进行修改的地方。
在Redis需要的不仅仅是一个字符串字面量,而是一个可以被修改的字符串值时,Redis就会使用SDS.
例:
set msg "hello,world";
Redis将在数据库中创建一个新的键值对:键是一个字符创对象,底层实现是一个保存着字符串"msg"的SDS。键值对也是一个字符串对象,底层实现是一个保存着字符串“hello,world”的SDS
SDS的结构体定义:
struct sdshdr{
//记录buf数组中已使用字节的数量
//记录SDS所保存字符串的长度
int len;
//记录buf数组中未使用字节的数量
int free;
//字节数组,用于保存字符串
char buf[];
}
为什么要使用SDS:
(1) 常数复杂度获取字符串长度:通过len属性
(2)避免缓存区溢出:
API需要对SDS进行修改时,API会先检查SDS的空间是否满足修改所需的要求,如果不满足的话,API会自动将SDS的空间拓展至执行修改所需的大小,然后才执行实际的修改操作。
(3)减少修改字符串时带来的内存重新分配次数:
两种优化策略:
①空间预分配:用于优化SDS的字符串增长操作,当SDS的API对一个SDS进行修改,并且需要对SDS进行空间拓展的时候,程序不仅会为SDS分配修改所必须要的空间,还会为SDS分配额外的未使用空间。
在拓展SDS空间之前,SDS API会先检查未使用空间是否足够,如果足够的话,API就会直接使用未使用空间,而无需执行内存重分配。
通过这种分配策略,SDS将连续增长N次字符串所需的内存重重分配次数从必定N次降低为最多N次。
②惰性空间释放:用于优化SDS的字符串缩短操作。
当SDS的API需要缩短SDS保存的字符串时,程序并不立即使用内存重分配来回收缩短后多出来的字节,而是使用free属性将这些字节的数量记录起来,并等待将来使用。
二进制安全:
所有SDS API都会以处理二进制的方式来处理SDS存放在buf数组里的数据。SDS的buf数组不是用来 保存字符,而是用来保存一系列二进制数据。
兼容部分c字符串函数:
API 总会将SDS保存的数据的末尾设置为空字符,并且总会在buf数组分配空间时多分配一个字节来容纳这个空字符,为了让那些保存文本数据的SDS可以重用一部分<string.h>库定义的函数
总结: