一:概述
- Redis 源码版本为3.0.0.
- Redis 没有直接使用C语言传统字符串表示,而是自己构建了一种 SDS(Simple dynamic string) 作为字符串代表。
- 目前官网的版本是 5.0发行版,6.0beat版本。对 SDS 又有了优化(主要优化了不同数据类型的存储)。
二:SDS 的定义
- 结构定义(src/sds.h)
-
- 示例展示
-
三:SDS 与 C 的区别。
- 获取字符串长度
- C 本身不记录字符串长度等信息,所以需要 O(N) 获取字符串长度。
- SDS 记录字符串长度信息(Len),所以通过 常数阶 O(1) 获取字符串长度。
- 意义
- 通过 使用 SDS ,Redis 将获取字符串长度由 O(N) 变为 O(1) ,确保了获取字符串长度不会成为系统的瓶颈。(即使字符串很长)
-
- 缓冲区溢出(buffer overflow)
- C 在修改字符串时, 如果在修改字符串时没有调整内存分配。
- 拼接字符串未分配内存,则会造成缓冲区溢出。
- 缩短字符串忘记释放内存,则会造成内存泄露。
- SDS 需要修改时,会优先检查 SDS 的空间是否满足所需要的空间,根据需求动态的分配 free,使得在扩展空间时,不会发生溢出。
- 优化策略 - 空间预分配(字符串扩张)
- 因为系统分配内存涉及到复杂的算法,为了避免字符串连续增长导致内存来回分配。除了分配修改字符串的内存,同时也会分配 free(未使用空间)。
- 字符串长度 < 1MB, 分配空间为 字符串长度 * 2
- 字符串长度 > 1MB, 分配空间为 字符串长度 + 1MB
-
- 优化策略 - 惰性空间释放(字符串缩减)
- 同理,当字符串缩短,SDS 会回收多余分配的 free。
-
四:二进制安全
- C 在保存 二进制/ASCIID等编码字符串时,除了末尾之外,字符不能包含空字符结尾( ),会被认为是结尾,导致字符串不完整。
- SDS 使用数组保存,不关心是否有问题。(可以保存视频,图像等)