Redis没有直接使用C语言传统的字符串表示,而是自己构建了一种名为简单动态字符串的抽象类型,并将SDS用作Redis的默认字符串表示;
1、使用场景:
数据库中的字符串值,AOF缓冲区,客户端状态中的输入缓冲区等;
2、定义
struct sdshdr{
int len;//记录buf数组中已使用字节的数量,等于SDS所保存字符串的长度;
int free;//记录buf数组中未使用字节的数量;
char buf[];//字节数组,用于保存字符串,柔性数组;
};
3、SDS与C字符串的区别
<1>字符串长度
如果求C语言中的字符串的长度,直到遇到’\0’结束,时间复杂度为O(n);而SDS中的字符串长度,有一个成员记录着字符串的长度,所以时间复杂度为O(1),这确保了获取字符串长度的工作不会成为Redis的性能瓶颈;
<2>杜绝缓冲区溢出
C语言中的strcat();利用这个函数进行字符串的拷贝时,这个函数内部是默认已经分配够空间的,如果我们在调用之前忘记给目的字符串分配够空间,那么就会发生字符串的溢出;而SDS中提供的接口sdscat(),如果空间不够,可以自动扩容;
<3>减少修改字符串时带来的内存重分配次数
a、空间预分配用于优化SDS的字符串增长的操作;如果SDS的长度小于1MB,那么程序分配和len属性同样大小的未使用空间;如果大于1MB,程序会分配1MB的未使用空间;
b、惰性空间释放用于优化SDS的字符串缩短的操作;当程序需要缩短SDS保存的字符串时,程序并不立即使用内存重分配来回收缩短后多出来的字节,而是使用free属性记录,将回收的空间记录起来;
4、二进制安全
C字符串中 的字符必须符合某种编码,并且除了字符串的末尾之外,字符串里面不能包含空字符,这个限制使得C字符串只能保存文本数据,而不能保存像图片、音频、视频、压缩文件这样的二进制数据;而SDS读取数据的时候,是根据len属性进行读取的,所以不存在遇到空字符串就结束的说法,SDS的API都是二进制安全的,所有SDS的API都会以处理二进制的方式处理存在SDS存放在buf数组里的数据,程序不会对其中的数据做任何限制、过滤,数据写入是什么样子,读取出来就是什么样子。把SDS中的buf称为字节数组是因为,它不是用buf来保存字符,而是用来保存一系列二进制数据。Redis不仅可以保存文本数据,还可以保存任意格式的二进制数据。
引用《Redis设计与实现》