简单动态字符串
redis的底层是C语言,但是没有简单的使用C语言传统的以空字符结尾的字符数组表示字符串。使用的是SDS表示字符串。
struct sdshdr {
//记录buf数组中已经使用的字节数量,等于SDS保存字符串长度(去除了结尾空字符串)
int len;
//记录buf中未使用的字节的数量
int free;
//字节数组,保存字符串
char buff[];
}
1.1 SDS与C字符串区别
常数复杂度获取字符串长度
杜绝缓冲区溢出
对buff进行操作的时候,若剩余空间不够,则先进行扩容再进行写入。
减少修改字符串时带来的内存重分配次数
修改N次字符串长度,最多执行N次内存重分配
redis作为数据库,数据可能会被频繁修改,而且速度要求很严苛。所以,若每次修改字符串的时候,都要进行内存重分配,就很浪费。
-
一:空间预分配:对SDS修改时需要空间扩展
- 扩展后的SDS的长度 小于1MB,则会分配一个和len属性相同大小的未使用空间。例如修改之后len变成13字节,则buff的实际长度是13+13+1=27字节(额外的字节保存空字节)
- 扩展后的SDS的长度 大于1MB,则会分配1MB未使用空间。例如修改之后len变成30MB,则buff的实际长度是30MB+1MB+1byte(额外的字节保存空字节)
-
二:惰性空间释放:用于优化SDS的字符串缩短操作
- 不会立刻使用内存重分配来回收缩短后多出来的字节。只会在有需要的时候释放。
二进制安全
为了确保redis可以存储各种数据,所以用sds,防止有些特殊字符无法展示。
兼容部分C字符串函数
链表
C语言没有内置实现链表,redis自己实现,通常用于redis中的列表键,发布与订阅,慢查询,监视器等。
typedef struct listNode {
struct listNode *prev;
struct listNode *next;
//节点的值
void *value
}listNode;
typedef struct list {
listNode *head;
//尾节点
listNode *tail;
//链表包含的节点数量
unsigned long len;
//节点值复制函数
void *(*dup) (void *ptr);
// 节点值释放函数
void (*free) (void *ptr);
// 节点值对比函数
int (*match) (void *ptr, void *key);
}list;
字典
用于保存键值对的抽象数据结构。