//
redis 字符串类型实现之SDS
//
在C语言中,使用以空字符结尾的字符数组来表示字符串,而在Redis中,并没有使用C这种类型,而是使用了sinple dynamic string ,简称SDS类型的字符串来作为Redis常用的数据结构。而将C类型的字符串仅仅用在一些无需对字符串值进行修改的地方。这两种字符串之间有些细微的差别今天在这里简单说说。
如果在redis客户端中执行set test "hello world"这条命令,将会在Redis数据库中创建一个新的键值对。其中:
key 是一个字符串对象,底层是一个内容为"test"的SDS
value 也是一个字符串对象,底层保存一个内容为"hello world"的SDS
到这里,就需要解释SDS的含义了,其实它是一个结构:
struct sdshdr
{
int len; //以使用的字节数量
int free; //未使用的字节数量
char buf[] //字节数组,用于保存字符串
}
假设我们存储一个hello的字符串,则:
len=5, free=0 , buf的值为[h,e,l,l,o, ]
从上面的结构中不难看出,在SDS中:
1、遵循以空字符结尾的习惯,这一点和C字符串类似
2、保存空字节的1个字节空间不计算在SDS的len值里面
3、分配空字节的空间、添加空字符到字符串末尾的操作都是由SDS函数自动完成
4、空字符对使用者完全透明
5、可以复用部分C的字符串函数库
和C字符串对比,SDS主要的优势有:
1、获取字符串长度的时候,不需要遍历整个字符串,复杂度为O(1),因为前期已经将字符串的长度写在len这个变量里面了。
2、空间分配策略改进。与C字符串不同,SDS在修改的时候,Redis的API会主动将SDS的大小扩展到执行修改所需要的大小,然后才执行实际的修改操作。而C字符串的修改,可能初选缓冲区溢出。
3、修改字符串的时候,SDS带来的内存重新分配次数比C字符串少。SDS中通过空间预分配和惰性空间释放两种方法,搭配len和free两个变量,来实现对内存分配策略的优化。C字符串中,更改字符串长度,内存就会重新分配,而SDS不需要每次都进行重新分配。
假设对"hello"这个SDS进行了修改,后面补上了"world",则需要重新对hello进行字节分配,则其长度变为10个字节,则程序会分配10个字节的未使用空间,则buf数组的实际长度将变成10+10+1=21个字节,最终buf中的内容是:[h,e,l,l,o,w,o,r,l,d, ]