SDS 是 Redis 使用的动态字符串实现。它在字符缓冲区之外保存长度与容量等元数据,使取长度、保存二进制数据和扩容更方便。SDS 是内部基础结构,String 是对外的数据类型,不能把两者直接画等号。
相比 C 字符串解决了什么问题?
C 字符串通常依靠末尾的 \0 判断结束,求长度需要扫描,无法仅用这套结束规则表达内部含零字节的数据。SDS 显式记录有效长度,因此可以保存序列化结果、图片片段等二进制内容,Redis 命令也按长度处理,而不是见到零字节就停止。
SDS 同时记录已分配空间。追加数据前可以检查容量,需要时重新分配,降低越界风险;在合适的扩容路径中预留空间,减少连续追加时每次都重新分配的成本。实现有不同大小的头部类型,以降低短字符串的元数据开销。扩容规则依版本和调用方式而变,不要把某一版本中的倍增阈值当成所有 Redis 的永久规范。
例如连续向字符串追加小段数据,如果每次都恰好分配新长度,就会频繁分配与拷贝。容量预留可以改善这个场景,但不会让无限增长的大字符串变成常数成本,最终仍受内存和搬移开销约束。
整数和短字符串编码
可表示为合适整数的 String 可能采用 int 编码;短字符串可能采用 embstr,把相关对象与字符串内存组织得更紧凑;其他情况通常采用 raw 编码并使用 SDS。这些是内存优化路径,应用不应依赖内部布局操作数据。
常见追问
SDS 求长度为什么通常是 O(1)?
长度保存在头部,读取元数据即可,不必扫描完整内容。字符串命令本身的整体复杂度仍要看实际操作。
SDS 完全不需要结尾的零字节吗?
实现仍会维护尾部零字节以方便与部分 C 接口配合,但有效数据长度以元数据为准,二进制安全不依赖零字节结束。
有容量记录就绝对不会发生缓冲区溢出吗?
它为安全操作提供信息,配套函数会检查与扩容;错误使用裸指针或存在实现缺陷仍可能出问题,不能把数据结构设计说成绝对保证。
SDS 的空闲容量会马上归还给 OS 吗?
不会必然立即归还。逻辑长度、分配容量和进程 RSS 是不同层面;具体释放由调用路径和内存分配器决定。