前言
PS:Redis有八种编码,但底层数据机构是六种。
二、SDS(simple dynamic string)简单动态字符串
结构定义
struct sdshdr{
//记录buf数组中已使用字节的数量
//等于 SDS 保存字符串的长度
int len;
//记录 buf 数组中未使用字节的数量
int free;
//字节数组,用于保存字符串
char buf[];
}
SDS保存的字符串结构图示:
优势:
常数复杂度获取字符串长度
由于 len 属性的存在,我们获取 SDS 字符串的长度只需要读取 len 属性,时间复杂度为 O(1)。
而对于 C 语言,获取字符串的长度通常是经过遍历计数来实现的,时间复杂度为 O(n)。通过 strlen key 命令可以获取 key 的字符串长度。
杜绝缓冲区溢出
在 C 语言中使用 strcat 函数来进行两个字符串的拼接,一旦没有分配足够长度的内存空间,就会造成缓冲区溢出。而对于 SDS 数据类型,在进行字符修改的时候,会首先根据记录的 len 属性检查内存空间是否满足需求,如果不满足,会进行相应的空间扩展,然后在进行修改操作,所以不会出现缓冲区溢出。
减少修改字符串的内存重新分配次数
空间预分配和惰性释放空间:在字符串修改时,长度增加时,C语言首先通过对内存的释放和申请来确保不会出现缓冲区溢出,减少时则可能发生内存泄漏,而SDS通过len和free属性来实现预分配和惰性释放。
空间预分配: Redis会提前申请大于实际需要内存空间,用free属性记录,用作后续的扩展,减少字符串增长后所需空间不足重新分配的过程。
惰性释放:当字符串修改操作,减少字符串长度时,使用free属性记录,而不是立即重新分配来释放多余空间,当然也可以手动的去释放多余空间。
二进制安全
在C语言中,字符串的结尾以空字符串 ‘\0’来进行标识,而在实际存储二进制文件时,可能会存在具有实际意义的空字符串,此时C语言无法正确的存取,而Redis是通过len字段来标识字符串是否结束,可以保证二进制安全。
兼容部分C字符串函数
SDS 除了保存数据库中的字符串值以外,SDS 还可以作为缓冲区(buffer):包括 AOF 模块中的AOF缓冲区以及客户端状态中的输入缓冲区