《Redis设计与实现》阅读笔记(二)--简单动态字符串

简单动态字符串

Redis只在一些无需对字符串进行修改的地方使用C字符串,大部分时候使用简单动态字符串simple dynamic string, SDS),字符串的抽象类型。二进制安全,可以存放任意格式的数据。

定义

 1 源码(部分):
 2 struct __attribute__ ((__packed__)) sdshdr5 {
 3     unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
 4     char buf[];
 5 };
 6 struct __attribute__ ((__packed__)) sdshdr8 {
 7     uint8_t len; /* used */
 8     uint8_t alloc; /* excluding the header and null terminator */
 9     unsigned char flags; /* 3 lsb of type, 5 unused bits */
10     char buf[];
11 };
12 书中代码:
13 struct sdshdr {
14     int len;
15     int free;
16     char buf[];
17 }

这里以书中代码为基础,len为使用的字节数,free表示已分配但未使用的字节数。buf就是char型数组保存字符串。

这里需要注意的是SDS保存的字符串沿用C字符串的格式,会在最末尾加一个'\0'表示字符串结束,好处是可以复用C语言的函数库。

举个例子:“hello” len为5,如果free为0,那么这个字符串一共使用6字节,'\0'额外使用一个字节。

由定义我们可以了解到,SDS的长度可以O(1)获得,而且他使用的内存不是长度+1。而且具有二进制安全的性质。

空间分配策略

Redis为了减少内存分配的次数,采用了空间预分配惰性空间释放两种策略。

空间预分配

当需要对SDS进行空间扩展的时候,SDS不仅会分配修改所必须的空间,还会进行预分配。

如果修改后的len值小于1M,那么就会预分配和len同样大小的预留空间。也就是说经过修改和预分配len和free的值是相等的。这时候占有的字节数就是len+free+1。

而如果修改后的len值大于等于1M,那么就只预分配1M空间。

惰性空间释放

当API需要缩短SDS保存的字符串,并不会立即释放多出来的字节,而是使用free记录下来。这样避免了内存重分配的操作,并为将来可能的增长提供了优化。

如果确实需要释放未使用的空间,SDS也提供了相应的API。

优点总结

  • 常数时间复杂度获取字符串长度
  • 杜绝缓冲区溢出
  • 减少在修改字符串长度时内存分配的次数
  • 二进制安全
  • 兼容部分C字符串函数

转载于:https://www.cnblogs.com/Star-Dust-/p/10331765.html

你可能感兴趣的:(《Redis设计与实现》阅读笔记(二)--简单动态字符串)