Redis设计与实现---SDS(simple dynamic string 简单动态字符串)

SDS(simple dynamic string 简单动态字符串)

struct sdshdr{
	//记录buf数组中已使用字节的数量
	//等于sds所保存字符串的长度
	int len;

	//记录buf数组中未使用字节的数量
	int free;

	//字节数组,用于保存字符串
	char buf[];
}

SDS与C字符串的区别:

  SDS C字符串
获取字符串长度

复杂度O(1)

直接读取len

复杂度O(N)

遍历整个字符串

缓冲区溢出

API是安全的,不会造成缓冲区溢出。

具体:

当SDS API需要对SDS进行修改时,API会先检查SDS的空间是否满足修改所需的要求,如果不满足的话,API会自动将SDS的空间扩展至执行修改所需的大小,然后才执行实际的修改操作。

API是不安全的,可能会造成缓存区溢出。

具体:

因为C字符串不记录自身的长度,所以strcat假定用户在执行这个函数时,已经为要拼接的字符串分配了足够的内存。

例:s1字符串分配内存不够,拼接s2字符串会造内存溢出。所以需要注意s1的内存是否分配的足够多。

内存重分配次数

修改字符串N次最多需要执行N次内存重分配。

具体:

减少修改字符串时带来的内存重分配次数

1、空间预分配

对SDS修改后,SDS的长度(即len属性的值)

(1)将小于1MB,那么程序分配和len属性同样大小的未使用空间,即len=free。例:

sds修改后长度变为13byte,那么len=free=13,该buf数组的实际长度为13+13+1=27。1为结束字符。

(2)将大于等于1MB,那么程序会分配1MB的未使用空间。例:sds修改后长度变为30MB,该buf数组的实际长度为30MB+1MB+1byte。

2、惰性空间释放

惰性空间释放用于优化SDS的字符串缩短操作:当SDS的API需要缩短SDS保存的字符串时,程序并不立即使用内存重分配来回收缩短后多出来的字节,而是使用free属性将这些字节的数量记录起来,并等待使用。

修改字符串N次必然执行N次内存重分配。
二进制安全

可以保存文本或者二进制数据。

SDS API都会以处理二进制的方式来处理。SDS存放在buf数组里的数据,程序不会对其中的数据做任何限制、过滤、假设,数据在写入时时什么样的,他被读取时就是什么样。所以称buf数组为字节数组,不是用来保存字符,而是用它来保存一系列二进制数据。

只能保存文本数据。

C字符串中的字符必须符合某种编码(比如ASCII),并且除了字符串的末尾之外,字符串里面不能包含空字符,否则最先被程序读入的空字符被误认为是字符串结尾,这些限制使得C字符串只能保存文本数据,不能保存像图片、音频、视频、压缩文件这样的二进制数据。

C字符串函数

可以使用一部分库中的函数。

兼容部分C字符串函数。

SDS遵循C字符串以空字符串结尾的惯例,以便可以重用一部分库定义的函数。

可以使用所有库中的函数。

总结,与C字符串相比,SDS具有以下优点:

1、常数复杂度获取字符串长度。   O(1)

2、杜绝缓冲区溢出。   自动扩展

3、减少修改字符串长度时所需的内存重分配次数。  (1)空间预分配(2)惰性空间释放

4、二进制安全。   buf数组保存二进制数据,而不是字符

5、兼容部分C字符串函数。   可以使用一部分库中的函数

你可能感兴趣的:(A)