面试题答案
一键面试Redis SDS 数据结构特点
- 柔性数组:SDS 结构体中包含一个柔性数组,用于存储实际的字符串内容。这样的设计使得字符串长度可以动态变化,而无需频繁分配和释放整个结构体。例如,在
struct sdshdr { int len; int free; char buf[]; }
中,buf
就是柔性数组。 - 记录长度信息:SDS 结构体中记录了字符串的长度
len
,获取字符串长度的操作时间复杂度为 O(1),而传统 C 字符串获取长度需要遍历到'\0'
,时间复杂度为 O(n)。 - 预分配策略:当对 SDS 进行修改时,如果需要重新分配内存,Redis 会采用预分配策略。即如果修改后长度小于 1MB,会额外分配和
len
相同长度的空间;如果大于 1MB,会额外分配 1MB 空间。这样减少了频繁的内存分配操作。 - 惰性空间释放:当缩短 SDS 字符串时,并不会立即释放多余的空间,而是记录在
free
字段中,供后续使用。
在数据压缩算法场景下对内存使用的优化
- 减少内存碎片:由于预分配策略和惰性空间释放,在数据压缩场景中,字符串的频繁修改(如拼接、截断等操作)不会产生大量内存碎片。例如,在使用 Lempel - Ziv - Welch(LZW)压缩算法处理字符串数据时,SDS 结构减少了因动态内存分配导致的内存碎片问题,提高了内存利用率。
- 减少内存分配次数:预分配策略减少了内存分配的次数。假设在数据压缩过程中,不断地将压缩后的小段数据拼接起来,如果使用传统 C 字符串,每次拼接都可能需要重新分配内存。而 SDS 预分配策略,减少了这种频繁的内存分配,例如原本可能需要分配 10 次内存,使用 SDS 预分配策略可能只需要分配 3 次。
优化效果举例
假设要对一个包含大量短字符串的文本进行压缩,使用传统 C 字符串,每处理一个短字符串并拼接,都需要重新分配内存。例如,处理 1000 个平均长度为 10 的短字符串拼接,每次拼接都要重新分配内存,会产生大量内存碎片,并且内存分配开销大。
而使用 SDS,由于其预分配策略,可能只需要分配少数几次内存(假设预分配策略使得每 100 个短字符串拼接只需要分配一次内存),大大减少了内存分配次数和内存碎片,提高了内存使用效率,在处理同样的 1000 个短字符串拼接时,内存使用更加高效,整体性能也得到提升。