前言:
全篇通过《Redis设计与实现》一书来进行梳理Redis原理的知识点,对于内容不会讲的特别深,有数据结构基础的同学可以看一下,主要是对知识点的一个梳理,如果有不懂的地方可以私信或者百度一下,知识点比较简单,适当的过一下可以帮助各位对Redis有一个新的认识
第一章:数据结构与对象
本章讲解的是Redis当初设计的数据结构和内部对象的知识点
1.动态字符串:
虽然Redis使用的是ANSI C所编写但是内部使用的字符串并没有使用C中的字符串,而是使用了一种名为简单动态字符串(simple dynarmic string,SDS)的抽象类型作为它的默认字符串类型
struct sdshdr{
//记录buf数组中已使用字节的数量
//等于SDS所保存字符串的长度
int len;
//记录buf数组中未使用字节的数量
int free;
//字节数组,用于保存字符串
char buf[];
}
SDS就是上面这种结构,比如我们存一个Redis字符串,那么在数组中存储的分别是‘R’,‘e’,‘d’,‘i’,‘s’五个字符,但是其中最后一个字节保留了空字符‘\0’,相信学习过C语言的同学肯定都知道为什么,那我就不细说了。
C中字符串不能满足Redis对字符串在安全性,效率以及功能这方面的要求,因此使用了SDS这种字符串结构。
1.1 常数获取字符串长度
不细说了,结构中有一个len属性可以直接获取。
1.2 杜绝缓存区溢出
因为C字符串不记录自身长度带来的一个问题就是容易造成缓冲区溢出,但是使用了SDS字符串后,我们完全杜绝了发生缓冲区溢出的可能性:当SDS API需要对SDS进行修改的时候,API会检查SDS的空间是否符合执行所需的大小,所以也就不会出现缓冲区溢出的情况了。如果长度不够会先进行扩展后再进行拼接。
1.3 减少修改字符串时带来的内存重分配次数
详细讲解起来比较麻烦我简单的说一下Redis是如何做的。
空间预分配
比如A字符串长度为N1,B字符串长度为N2,那么当需要相加的时候我们为其进行一次分配,直接将长度扩容为N1+N2+1的长度,如果这时再有C字符串长度N3需要替换B字符串,如果B字符串长度大于C字符串那么容器长度不变,但是free属性数据会进行改变。
惰性空间释放
就是扩容后不会回缩,哪怕数据没有填满也会保持扩容后的长度,但是我们拥有API可以进行修改。
1.4 二进制安全
这个就不细说了,有兴趣的自己去看看。
1.5兼容部分C字符串函数
遵循C字符串以空字符结尾的惯例可以帮助SDS可以重用<string.h>库定义的函数。