Redis之简单动态字符串SDS

1.用途

Redis并未使用c语言的string,而是自己构建简单动态字符串(SDS,simple dynamic string)抽象类型表示字符串.

​ c语言string只是用在不需要修改的地方,例如日志打印.其他地方基本都是SDS,例如:

redis>RPUSH fruit "apple" "banana" "cherry"

除了保存字符串值外,还用于缓冲区buffer:

​ AOF中AOF缓冲区,客户端状态中输入缓冲区

2.定义

SDS:
struct sdshdr{
	int len;	//记录buf数组已使用字节数=SDS保存字符串长度
	int free;	//buf数组中未使用字节数
	char buf[]; //字节数组char类型数组,保存字符串
}

key(就是sdshdr),free,len,buf. 其中buf指向char数组,其中存储sds字符串内容,以\0结尾,free和len都不计算\0所占空间

例如free=5,len=5,buf指向的为sds字符串占用5个,\0占用1个,空占用5个.有空画图

3.SDS与c字符串区别

### 3.1 常数复杂度获取字符串长度

​ 由于记录了len,所有strlen获取字符串长度O(1),c中遍历O(n)

3.2 杜绝缓冲区溢出

c中字符串不记录长度容易造成缓冲区溢出,sds api修改sds时,api先检查空间是否足够,不够自动空间扩展后再修改(全自动避免缓冲区溢出)

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

SDS通过未使用空间接触了字符串长度和底层数组长度之间的关联.有了free属性在,buf数组长度不一定是+1,因为其中可以包含未使用字节.

​ 未使用空间帮助SDS实现了 1.空间预分配 2.惰性空间释放 两种优化策略

3.3.1.空间预分配(增)

​ 用于优化SDS字符串增长操作.

​ 对SDS进行空间扩展时,不仅给SDS分配修改所必需的空间,还会给SDS分配额外未使用空间:

​ 如果修改后SDS长度(len)小于1MB,分配与len同样的未使用空间(len*2).实际长度变成len(SDS修改后实际长度)+len(未使用空间)+1byte,不计入len长度

​ 如果修改后SDS长度(len)大于等于1MB,分配1MB未使用空间,实际长度变成len(SDS修改后实际长度)+1MB(未使用空间)+1byte,1byte就是\0

多分配的未使用空间使增长n次字符串需要的内存重分配次数从必定n次变成最多n次

3.3.2.惰性空间释放(减)

​ 用于优化SDS字符串缩短操作

​ 需要缩短SDS保存的字符串时,不立即使用内存重分配缩短多余字节,而是使用free记录多余字节等以后使用.

sdstrim(s,"xy")==>a,b,c,\0移动到最左,x,y空间清空,保留未使用空间.len=3,free=9,\0

以后扩增SDS时,如果free足够,不需要执行内存重分配,直接使用未使用空间.

3.4 二进制安全

​ c语言字符串不能存图形等,如果包含空字符,会被认为字符串结尾,限制C语言字符串不能存图片等.

​ SDS处理存放在buf数组中的数据不会做任何改变,所以buf属性被称为字节数组--->redis不是用buf字节数组保存字符,而是保存二进制数据.

​ 1.保存二进制数据,存入数据不变化.

​ 2.用len属性而不是空字符串或者判断字符串是否结束

4.SDS API

​ sdsnew:创建包含给定c字符串的sds

​ sdsempty:创建空sds

​ sdsfree:释放sds

​ sdslen:返回len(byte数)

​ sdsavail:返回free(byte)

​ sdsdup:创建给定sds副本(copy)

​ sdsclear:清空sds中字符串

​ sdscat:将给定c字符串拼接到sds字符串末尾

​ sdscatsds:将给定sds字符串拼接到sds字符串末尾

​ sdscpy:将给定c字符串复制到sds,覆盖sds原有字符串

​ sdsgrowzero:用空字符串将sds扩展到给定长度

​ sdsrange:保留sdsd给定区间内数据,不在区间内数据会被覆盖或清除

​ sdstrim:从给定sds左右两端移除所有在给定c字符串中出现过的字符

​ sdscmp:对比两个sds字符串是否相同

猜你喜欢

转载自blog.csdn.net/qq_41834553/article/details/113603304