SDS(Simple Dynamic String)简单动态字符串。
Redis除了字面量用的C语言的字符串变量,其余都是使用的SDS。
sds.h/sdshdr源码:
struct sdshdr { //长度,为字符数组长度-1 int len; //分配待用的数组长度 int free; //字节数组,为了共用C语言的一些处理字符串的函数还在字符后加'\0' char buf[];}
对比C语言字符串的优势:
- 常数复杂度获取字符串长度
- 杜绝缓冲区溢出
- 减少修改字符串长度时需要的内存重分配次数
- 二进制安全
- 兼容部分C字符串函数
常数复杂度获取字符串长度
C字符串要获得长度需要遍历整个字符串数组,复杂度O(N),而SDS结构中的len可以直接获取当前字符串长度,复杂度O(1)。
杜绝缓冲区溢出
C字符串当需要拼接字符串,如果不重新分配内存,拼接后可能会覆盖连续内存的值造成缓冲区溢出,而SDS通过free记录的安全已分配空闲空间的数组长度,如果要拼接的字符串长度大于free,会先重新奉陪空间再凭借。
分配规则如下:
- 当len长度小于1MB,再分配len大小的数组空间
- 当len长度大于等于1MB,再分配1MB大小数组空间
减少修改字符串长度时需要的内存重分配次数
C字符串每次修改都需要执行重分配内存,如拼接之前不执行重分配内存会产生缓冲区溢出,缩短字符串之前不自信重分配内存会产生内存泄漏。而内存重分配涉及算法浮渣,且可能需要执行系统调用,所以通常比较耗时,所以如果直接使用C语言作为Redis字符串结构显然不理想。
而SDS的free空间减少了内存重分配次数。
二进制安全
SDS使用char数组存储二进制数据,所以二进制安全。
兼容部分C字符串函数
SDS数组会在数据的后面加一个'\0'表示字符串的结束,'/0'用户不感知,也不会反应在len长度中,这样做是为了与C字符串保持统一,兼容部分C字符串函数。