数据结构-SDS
redis中对string值的存储,并没有使用C中的char*,而是使用了SDS (simple dynamic string)SDS结构类似Go里的切片,有3个字段,总长度alloc(类似capacity),已用长度len,以及实际字符串数组char*相对于
C的char*,有如下优势:二进制安全的(不用原字符串 +
\0的方式表示结束)能在
O(1)的时间获取字符串长度预留了额外空间,追加字符串时可能不需要重新分配空间;(惰性释放,内存紧张时也会释放)
// 空间占用为3B + 字符串长度
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* 已使用的长度 used */
uint8_t alloc; /* 分配的总长 excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};SDS 的编码
SDS的实现有2种,在长度特别短时,使用embstr形式存储,而当长度超过44字节时,使用raw形式存储。两者其实都是
header+char*的组合。embstr比raw少一次内存空间分配,它把header和 字符串保存在同一块连续的内存里了。而raw要申请额外内存保存字符串。
为啥是
44字节?
64字节,减去RedisObject头信息19字节,再减去3字节SDS头信息,再减去\0结尾,这样最后可以存储44字节。
Append 函数的实现
新字符串长度 = (原有长度 + 新长度)+ 预分配空间
预分配空间的算法如下:
sds sdsMakeRoomFor(sds s, size_t addlen) {
newlen = (len+addlen); // 追加后的长度
if (newlen < SDS_MAX_PREALLOC) // 1MB
newlen *= 2; // 上次用了len长度的空间,那么下次程序可能也会用len长度的空间,所以redis就为你预分配。这个有点谜
else
newlen += SDS_MAX_PREALLOC;
}Last updated