1 数据结构与对象
1.1 简单动态字符串
SDS简单动态字符串(simple dynamic string,SDS)是Redis中字符串的底层数据结构。
struct sdshdr {// 记录 buf 数组中已使用字节的数量// 等于 SDS 所保存字符串的长度int len;// 记录 buf 数组中未使用字节的数量int free;// 字节数组,用于保存字符串char buf[];};
底层数据结构遵循C语言中空字符"\0"结尾。
数据结构三个属性分别代表存储字节的数组buf,数组中存储字符的长度len,数组空闲长度free。
注意保存\0的字符串并不占用len的长度。并且会为\0空字符分配额外一字节空间。
遵循空字符结尾这一惯例的好处是, SDS 可以直接重用一部分 C 字符串函数库里面的函数。
以下是C语言中的字符数组与SDS的区别
1.1.1 获取字符串长度时间复杂度
SDS计算字符串长度的时间复杂度是O(1),C语言需要遍历数组计算长度时间复杂度为O(n)
1.1.2 缓冲区溢出
C语言中strcat的执行会导致缓冲区溢出。但SDS由于记录了字符串长度,sdscat在拼接字符串前会先检查SDS中的buf数组空间是否足够,不足的时候会先扩容buf,再执行拼接工作。
1.1.3 减少字符串修改时内存重分配次数
SDS中未使用空间可以减少字符串修改时,内存的重分配次数。
1.1.4 空间预分配
SDS被修改后,如果SDS的长度小于1MB,那么程序将分配len长度的空闲空间。例如len为20字节,那么同样分配20字节的free空间。
SDS被修改后,如果SDS的长度大于1MB,那么程序将分配1MB长度的free空闲空间。
1.1.5 惰性空间释放
SDS修改时,字符串的缩短并不减少buf实际长度,而是将增加字符串的free的长度。
但是SDS也提供真正缩短字符串的API
1.1.6 二进制安全
C语言中,字符数组不能包含空字符,会被识别为字符串结尾。因此C语言的字符数组只能保存文本数据。
但SDS中不对数据内容做限制,SDS存放的是二进制数据,因此SDS中叫buf为字节数组。SDS中通过len的参数来判断数据的结尾。而不是\0字符。这也保证了SDS的二进制安全
1.1.7 兼容部分c语言中的字符串函数
SDS也通过在数组最后存放\0字符来兼容C语言中的字符串函数。
例如:strcasecmp,strcat
C 字符串 | SDS |
---|---|
获取字符串长度的复杂度为 。 | 获取字符串长度的复杂度为 。 |
API 是不安全的,可能会造成缓冲区溢出。 | API 是安全的,不会造成缓冲区溢出。 |
修改字符串长度 N 次必然需要执行 N 次内存重分配。 | 修改字符串长度 N 次最多需要执行 N 次内存重分配。 |
只能保存文本数据。 | 可以保存文本或者二进制数据。 |
可以使用所有 <string.h> 库中的函数。 | 可以使用一部分 <string.h> 库中的函数。 |