726 字
4 分钟
Redis 为什么使用 SDS,而不是 C 字符串?
  1. 1Redis 系列导读:知识地图、必会主线与复习顺序
  2. 2Redis 中常见的数据类型有哪些?
  3. 3Redis 通常应用于哪些场景?
  4. 4Redis为什么这么快?
  5. 5Redis 常用的过期时间、删除 Key 命令有哪些?
  6. 6Redis 的过期 Key 是如何被删除的?
  7. 7Redis 内存满了怎么办?有哪些淘汰策略?
  8. 8缓存穿透、击穿、雪崩的区别与解决方案
  9. 9Redis 如何保证缓存与数据库的数据一致性?
  10. 10Redis 的持久化机制有哪些?
  11. 11Redis 主从复制的完整流程是什么?
  12. 12Redis 的哨兵机制是什么?
  13. 13Redis Cluster 模式与 Sentinel 模式的区别是什么?
  14. 14Redis 支持事务吗?如何实现?
  15. 15Redis 中如何实现分布式锁?
  16. 16Redis 的 Lua 脚本功能是什么?如何使用?
  17. 17如何解决 Redis 中的热点 Key 问题?
  18. 18Redis BigKey 有什么危害?如何发现和治理?
  19. 19为什么 Redis 设计为单线程?6.0 版本为何引入多线程?
  20. 20Redis 的 LRU 和 LFU 有什么区别?
  21. 21Redis 数据类型和底层编码有什么区别?
  22. 22Redis 中跳表的实现原理是什么?
  23. 23Redis 的 ZSet 为什么使用跳表,而不是平衡树?
  24. 24Redis 的 RDB 快照如何生成?为什么会有写时复制?
  25. 25Redis 的 AOF 刷盘和重写有什么区别?
  26. 26Redis 断线后如何通过 PSYNC 部分重同步?
  27. 27Redis 主从切换为什么会丢数据?WAIT 能解决吗?
  28. 28Redis 集群会出现脑裂问题吗?
  29. 29Redisson 看门狗(watch dog)机制了解吗?
  30. 30Redis Cluster:哈希槽、Gossip 与故障转移
  31. 31Redis Pipeline 为什么能提高吞吐?能保证原子性吗?
  32. 32Redis 的 SCAN 和 KEYS 有什么区别?
  33. 33Redis 变慢时如何排查?SLOWLOG 能看到所有耗时吗?
  34. 34Redis 和 MySQL 有什么区别?
  35. 35Redis 为什么使用 SDS,而不是 C 字符串?本文
  36. 36Redis 的哈希表如何处理冲突和渐进式 rehash?
  37. 37Redis Cluster 的 MOVED 和 ASK 重定向有什么区别?
  38. 38Redis Cluster 为什么会报 CROSSSLOT?Hash Tag 怎么用?
  39. 39Redis 如何实现限流?固定窗口和滑动窗口怎么选?
  40. 40Redis Stream 如何保证消息消费?ACK 和 PEL 是什么?
  41. 41Redis 删除数据后为什么内存不下降?如何理解内存碎片?

SDS 是 Redis 使用的动态字符串实现。它在字符缓冲区之外保存长度与容量等元数据,使取长度、保存二进制数据和扩容更方便。SDS 是内部基础结构,String 是对外的数据类型,不能把两者直接画等号。

相比 C 字符串解决了什么问题?#

C 字符串通常依靠末尾的 \0 判断结束,求长度需要扫描,无法仅用这套结束规则表达内部含零字节的数据。SDS 显式记录有效长度,因此可以保存序列化结果、图片片段等二进制内容,Redis 命令也按长度处理,而不是见到零字节就停止。

SDS 同时记录已分配空间。追加数据前可以检查容量,需要时重新分配,降低越界风险;在合适的扩容路径中预留空间,减少连续追加时每次都重新分配的成本。实现有不同大小的头部类型,以降低短字符串的元数据开销。扩容规则依版本和调用方式而变,不要把某一版本中的倍增阈值当成所有 Redis 的永久规范。

例如连续向字符串追加小段数据,如果每次都恰好分配新长度,就会频繁分配与拷贝。容量预留可以改善这个场景,但不会让无限增长的大字符串变成常数成本,最终仍受内存和搬移开销约束。

整数和短字符串编码#

可表示为合适整数的 String 可能采用 int 编码;短字符串可能采用 embstr,把相关对象与字符串内存组织得更紧凑;其他情况通常采用 raw 编码并使用 SDS。这些是内存优化路径,应用不应依赖内部布局操作数据。

常见追问#

SDS 求长度为什么通常是 O(1)?#

长度保存在头部,读取元数据即可,不必扫描完整内容。字符串命令本身的整体复杂度仍要看实际操作。

SDS 完全不需要结尾的零字节吗?#

实现仍会维护尾部零字节以方便与部分 C 接口配合,但有效数据长度以元数据为准,二进制安全不依赖零字节结束。

有容量记录就绝对不会发生缓冲区溢出吗?#

它为安全操作提供信息,配套函数会检查与扩容;错误使用裸指针或存在实现缺陷仍可能出问题,不能把数据结构设计说成绝对保证。

SDS 的空闲容量会马上归还给 OS 吗?#

不会必然立即归还。逻辑长度、分配容量和进程 RSS 是不同层面;具体释放由调用路径和内存分配器决定。

Redis 为什么使用 SDS,而不是 C 字符串?
https://blog.xqcherry.top/posts/interview/redis/redis-sds/
作者
xqcherry
发布于
2026-10-12
许可协议
CC BY-NC-SA 4.0