Sds (Simple Dynamic String,简单动态字符串)是Redis 底层所使用的字符串表示,它被用在几乎所有的Redis 模块中。
Sds 在Redis 中的主要作用有以下两个:
1. 实现字符串对象(StringObject);
对于那些包含字符串值的字符串对象来说,每个字符串对象都包含一个sds 值。
举个例子: SET java "redis"
这个键值对的键和值都是字符串对象,它们都包含一个sds 值。
2. 在Redis 程序内部用作char* 类型的替代品;(Redis 使用sds 而不是传统C 字符串的原因。)
因为char* 类型的功能单一,抽象层次低,并且不能高效地支持一些Redis 常用的操作(比如追加操作和长度计算操作),所以在Redis 程序内部,绝大部分情况下都会使用sds 而不是char* 来表示字符串。总结起来封装sds数据结构就是为了更高效,使用起来更简单。
Sds 的实现
Sds是Redis 底层所使用的字符串表示,Redis 使用sds 类型替换了C 语言的默认字符串表示:sds 既可以高效地实现追加和长度计算,并且它还是二进制安全的
typedef char * sds; //类型sds 是char * 的别名
struct sdshdr { //结构sdshdr 则保存了len 、free 和buf 三个属性。
// buf 已占用长度
int len;
// buf 剩余可用长度
int free;
// 实际保存字符串数据的地方
char buf[];
};
注意,当调用SET 命令创建sdshdr 时,sdshdr 的free 属性为0 ,Redis 也没有为buf 创建额外的空间——而在执行APPEND 之后,Redis 为buf 创建了多于所需空间一倍的大小。
在这个例子中,保存"hello world again!" 共需要18 + 1 个字节,但程序却为我们分配了18 + 18 + 1 = 37 个字节——这样一来,如果将来再次对同一个sdshdr 进行追加操作,只要
追加内容的长度不超过free 属性的值,那么就不需要对buf 进行内存重分配。
Note: 这种分配策略会浪费内存吗?
开发提示:尽量减少字符串频繁修改操作如append,setrange, 改为直接使用set修改字符串,降低预分配带来的内存浪费和内存碎片化。