概览
SDS 是 Redis 字符串底层实现的数据结构,全称 Simple-Dynamic-String 简单动态字符串,对 C 语言的字符串进行了增强,增强主要体现在效率和安全性方面。
定义
SDS数据结构如下,主要包含三个属性:字符串长度,空闲空间,字符数组
另外 SDS 遵守了C语言字符串以空字符结尾的惯例,这样做的原因是可以复用C语言库中部分字符串操作相关的函数。
常数复杂度获取字符串长度
由于 SDS 会维护 len 属性记录字符长度,不需要像 C语言字符串一样通过遍历字符串得到长度,因此在获取字符串长度上面SDS有着很高的效率,时间复杂度仅为O(1)。
避免缓冲区溢出
C语言中因字符串内容修改,使得字符串长度发生变更的时候,在内存分配的原则上是用多少,分配多少,而分配内存的操作需要用户自主完成,容易因为操作失误而导致缓冲区溢出问题,例如修改前忘记预分配内存,导致修改后的字符串内容溢出到了其它字符串上。
而 SDS 维护了 free 空闲空间字段,可以动态判断当前空闲空间是否足够容纳扩展后的字符串内容,如果空间不足,则会自动扩容,避免了缓存溢出的问题。
减少重分配次数
上面讲到,在内存空间不足时,SDS 会触发自动扩容,扩容机制如下:
- 如果修改后的字符串长度 len < 1MB,则会分配与 len 同样大小的空闲空间,即 free = len,最终扩容后的总空间大小 = len + free + 1byte
- 如果修改后的字符串长度 len >= 1MB,则会分配 1MB 的空闲空间,即 free = 1MB,最终扩容后的总空间大小 = len + 1MB + 1byte
通过空间预分配策略,SDS 可以减少连续执行字符串增长操作所需的内存重分配次数。
另外在字符串缩短的场景下,SDS 不会立即回收多出来的空闲空间,通过 free 属性将空闲空间记录下来,并等待将来使用。
通过惰性空间释放机制,SDS 能避免因字符串缩短操作导致的内存重分配,也为将来可能有的增长操作提供了基础。
与此同时,SDS也提供了相应的API,可以在有需要时真正地释放SDS的未使用空间。
二进制安全
C语言字符串以空字符作为字符串结 尾的标识,因此除尾部字符外,字符串中不能包含空字符,否则会导致字符串被提前截断。
这样使得C语言字符串只能保存文本数据,而不能保存像图片、音频、视频、压缩文件这样的二进制数据。
而 SDS API都会以处理二进制的方式来处理存放在buf数组里的数据,程序不会对其中的数据做任何限制、过滤、或者假设,数据在写入时是什么样的,它被读取时就是什么样。
因此 SDS 也是二进制安全的,除了可以保存文本内容,也可以保存二进制数据。
|