SDS(simple dynamic string) 简单动态字符串
SDS数据结构
struct sdshdr{
// 记录buf数组中已使用的字节的数量
int len;
// 记录buf数组中未使用的字节的数量
int free;
// 字节数组,用于保存字符串
char buf[];
};
SDS与C字符串的区别
C字符串总是用长度为N+1的字符数组来表示长度为N的字符串,并且字符串数组的最后一个元素总是字符'\0'。
SDS常数复杂度获取字符串长度,而C字符串则是O(N)。
SDS杜绝缓冲区溢出。这一点通过SDS的空间分配策略决定。在SDS API需要对字符数组进行修改时,API首先检查SDS的空间是否满足修改的需求,如果不满足,API会自动将SDS的空间扩展至执行修改所需的大小。
SDS是二进制安全的。而C字符串必须符合某种编码(例如ASCII),并且除了字符末尾之外,不可以包含空字符,否则最先被程序读到的空字符将被认为是字符串结尾。因此,这限定了C字符串只能保存文本数据,而不能保存图片,音频,视频等。而SDS则适用于各种不同的处理场景,SDS的API都是以处理二进制数据的方式来处理SDS存放在buf数组中的数据,程序不会对存放在其中的数据做任何限定,过滤或者假设。数据在被写入时候是什么样,读取时候就是什么样。
SDS减少修改字符串时候带来的内存重分配
SDS通过未使用空间解除了字符串长度和底层数组长度之间的关联。
SDS实现了两种空间优化策略:空间预分配,和惰性空间释放。
1.空间预分配
当SDS的API对一个SDS修改,并且需要对SDS进行空间扩展的时候,程序不仅会为SDS分配修改所需的空间,还会为SDS分配额外的未使用空间。
如果对SDS进行修改之后,SDS的长度将小于1MB,那么程序分配和len属性同样大小的未使用空间,这时SDS的len属性的值和free属性的值相同。
如果对SDS修改之后,SDS的长度将大于1MB,那么程序会分配1MB的未使用空间。
在扩展SDS空间之前,SDS API会首先判断未使用空间是否足够,如果足够的话,API就会直接使用未使用空间,而无需执行内存重分配。
通过这种预分配策略,SDS将连续增长N次字符串所需的内存重分配次数从必定N次降低为最多N次。
2.惰性空间释放
惰性空间释放用于优化SDS的字符串缩短操作:当SDS的API需要缩短SDS保存的字符串时,程序并不立即使用内存重分配来回收缩短之后多出来的字节,而是使用free属性将这些字节的数量记录起来,并等待将来使用。