内部实现
1 | struct sdshdr { |
c 字符串通常是以空字符 ‘\0’ 结尾,所以一个 SDS 的长度为: len + free + 1
与 c 字符串的区别
类型 | c 字符串 | SDS |
---|---|---|
获取字符串长度 | O(N) | O(1) |
是非 API 安全 | 存在缓冲区溢出风险 | API 安全,无缓冲区溢出 |
是否二进制安全 | 非二进制安全 | 二进制安全 |
修改字符串导致内存分配 | 每次重新分配 | N 次修改最多 N 次分配 |
是否兼容 <string.h> 标准库 | 完全兼容 | 部分兼容 |
获取字符串长度
- c 字符串获取长度是逐个读取字符计算长度,时间复杂度为: O(N)
- SDS 是通过
len
来获取字符串长度,时间复杂度为: O(1)
API 安全
- c 字符串不会检查内存空间是否足够,当拼接字符串时,有可能会出现缓冲区溢出问题
- SDS 则会根据
free
来判断空间是否足够,如果内存空间不足,则会申请内存空间,因此不会有缓冲区溢出问题
二进制安全
- c 字符串是根据空字符
\0
来判断字符串是否结束,因此字符串中间不能有空字符, 只能用来保存文本内容,无法保存二进制数据 - SDS 是通过
len
来判断字符串是否结束,因此既可以保存文本内容,又可以保存二进制数据
内存分配
- c 字符串每次修改内容时都需要进行重新的内存分配
- SDS 则是根据
free
判断空间是否足够,如果不足,重新内配, 并且当修改后的len
< 1M 时, 额外多分配len
的长度, 此时free
=len
; 当缩短 SDS 字符串内容时, 并不会立即释放空间, 而是通过将free
变大,记录剩余空间,以减少之后的再分配。(通过惰性释放避免内存浪费问题)