Redis--SDS空间分配策略(len、free、buff[])
SDS结构(简单动态字符串)
结构如下
struct stdhdr {
int len //记录buff数组中已使用字节的数量
int free //记录buff数组中未使用字节的数量
char buff[] //字节数组,用于保存字符串
}
(1)free 属性为0,表示这个SDS没有分配任何未使用空间。
(2)len 属性为5,表示这个SDS保存着一个5字节长的字符串
(3)buf 属性是一个char类型的数组,数组的前五个字节分别保存了,'R' 'e' 'd' 'i' 's' ,而最后一个字节保存了空字符 '\0' (以空字符结尾),最后一个空字节不计算在len属性里面。
SDS字符串和C字符串的区别
1.通过使用SDS字符串(len记录字符串长度),使得获取字符串长度的复杂度从O(N)变为O(1)
2.杜绝缓存区溢出,C字符串不记录自身长度,在拼接字符串时可能造成缓存区溢出
3.通过未使用空间free,减少修改字符串带来的内存重分配次数
空间预分配
空间预分配用于优化 SDS 的字符串增长操作: 当 SDS 的 API 对一个 SDS 进行修改, 并且需要对 SDS 进行空间扩展的时候, 程序不仅会为 SDS 分配修改所必须要的空间, 还会为 SDS 分配额外的未使用空间。
其中, 额外分配的未使用空间数量由以下公式决定:
- 如果对 SDS 进行修改之后, SDS 的长度(也即是 len 属性的值)将小于 1 MB , 那么程序分配和 len 属性同样大小的未使用空间, 这时 SDS len 属性的值将和 free 属性的值相同。 举个例子, 如果进行修改之后, SDS 的 len 将变成 13 字节, 那么程序也会分配13 字节的未使用空间, SDS 的 buf 数组的实际长度将变成 13 + 13 + 1 = 27 字节(额外的一字节用于保存空字符)。
- 如果对 SDS 进行修改之后, SDS 的长度将大于等于 1 MB , 那么程序会分配 1 MB 的未使用空间。 举个例子, 如果进行修改之后, SDS 的 len 将变成 30 MB , 那么程序会分配 1 MB 的未使用空间, SDS 的 buf 数组的实际长度将为 30 MB + 1 MB + 1 byte 。
通过空间预分配策略, Redis可以减少连续执行字符串增长操作所需的内存重分配次数。
惰性空间
释放惰性空间释放用于优化SDS的字符串缩短操作:当 SDS的API需要缩短 SDS保存的字符串时, 程序并不立即使用内存重分配来回收缩短后多出来的字节, 而是使用 free 属性将这些字节的数量记录起来, 并等待将来使用。