Redis-简单动态字符串

Reids没有直接使用C语言传统的字符串表示,而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类型,并将SDS用作Redis的默认字符串表示。

SDS的类型定义

 struct sdshdr{
 //记录buf数组中已使用字节的数量,等于SDS所保存字符串的长度
 int len;
 //记录buf数组中位数字字节的数量
 int free;
 // 字节数组,用于保存字符串
 char buf[];
 }

其中SDS遵循C字符串以空字符串结尾的管理,保存空字符的1字节不计算在SDS的len属性里边

SDS与C字符串的区别

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

C字符串并不记录自身的长度信息,所以获取C字符串长度,需要遍历数组,所以操作复杂度为O(N),而SDS在len属性中记录了SDS本身的长度获取复杂度为O(1)

避免缓冲区溢出

当SDS API需要对SDS进行修改时,API会先根据free属性来检查SDS的剩余空间十分满足,
如果不满足,API会自动将SDS的空间扩展至执行修改所需要的大小,然后才执行实际的修改操作,所以使用SDS不需要手动修改SDS的空间大小,可以避免缓冲区溢出问题。

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

1.空间预分配策略
空间预分配用于优化SDS的字符串增长操作:当SDS的API对一个SDS进行修改,并且需要对SDS
进行空间扩展的时候,程序不仅会为SDS分配修改所需要的空间,还会为SDS分配额外的未使用空间。
空间预分配公式
SDS的len< 1MB ,则设置free和len属性值相同,表示预分配一倍的空间数组;
SDS的len>= 1MB,则预分配1MB的未使用空间。
2.惰性空间释放策略
惰性空间释放用于优化SDS的字符串缩短操作:当SDS的API需要缩短SDS保存的字符串时,程序
并不立即使用内存重新分配来回收缩短多出来的字节,而是使用free属性,将这些字节的
数量记录下来,并等待将来使用。与此同时,SDS也提供了相应的API,让我可以在有需要时,
真正的释放SDS的使用空间,可以不用担心惰性空间释放策略会造成内存浪费。

二进制安全

C字符串中的字符必须符合某种编码,并且除了字符串的末尾之外,字符串里边不能包含空字符,
否则最先被程序读入的空字符串被误认为是字符串结尾,这些限制使的C字符串只能保存文本数据,不能保存图片、音频、视频、压缩文件等二进制数据。
而SDS使用len属性来判断字符串是否结束,不会对buf数组里的数据进行任何限制过滤等操作。
使得SDS可以保存任意格式的二进制数据。

兼容部分C字符串函数

虽然SDS的API是二进制安全的,但是一样遵循了C字符串以空字符串结尾的惯例,使得
SDS可以重用一部分C字符串库定义的函数。

C字符串和SDS之间的区别

C字符串 SDS
获取字符串长度的复杂度为O(N) 获取字符串长度的复杂度为O(1)
API不安全,可能会造成缓冲区溢出 API安全,不会造成缓冲区溢出
修改字符串长度N次需要执行N次内存重分配 空间预分配,避免每次都进行内存重分配
只能保存文本数据 可以保存文本或者二进制数据
可以使用所有字符库中函数 可以使用部分字符库中的函数

你可能感兴趣的:(Redis-简单动态字符串)