Redis数据结构(一)简单动态字符串

Redis的字符串采用的是自定义的struct,名字叫做简单动态字符串(simple dynamic string,SDS)。

结构如下:

struct sdshdr{int len;int free;char buf[];};采用如此结构的好处是:【1】获取length的时候复杂度为O(1),不需要O(n);【2】动态分配空间,避免缓冲区溢出,避免每次修改或者append都重新分配;【3】二进制安全; 关于第一点显而易见,第二点,,为了减少修改字符串带来的内存重分配次数,redis采用了2个措施: 1)空间预分配;假设如下sds(状态【0】),执行命令【sdscat(s,”redis”)】往其中append一个字符串“redis”之后将变为状态【1】,注意加上结尾符号“\0”其实总共21字节;这里面发生了什么呢?当sds发现当前free长度无法分配新添加的字符串时,将发生一次空间分配,如果修改之后sds长度小于1MB,则会分配总长度为【修改后长度】*2+1,即为(5+5)*2+1,1为结尾符号空间。如果修改后sds总长度大于等于1MB,则会分配【修改后总长度】+1MB的长度。 假设再次执行命令【sdscat(s,”redis”)】,由于当前状态【1】free=10,有足够空间分配新加入的字符串,则不会发生空间分配操作,变为状态【2】;

状态【0】:

struct sdshdr{ int len=5; int free=4; char buf[]={‘h’,’e’,’l’,’l’,’o’,’\0′,”,”,”,”}; };

状态【1】:

struct sdshdr{ int len=10; int free=10; char buf[]={‘h’,’e’,’l’,’l’,’o’,’r’,’e’,’d’,’i’,’s’,’\0′,…}; };

状态【2】:

struct sdshdr{ int len=15; int free=5; char buf[]={‘h’,’e’,’l’,’l’,’o’,’r’,’e’,’d’,’i’,’s’,’r’,’e’,’d’,’i’,’s’,’\0′,…}; }; 2)惰性空间释放;现在假设从状态【2】执行命令【sdstrim(s,”re”)】,移除sds中所有的’r’,’e’,将转换为状态【3】;此时并没有释放空间,len+free依然等于20;这样做的目的是避免了缩短字符串时的内存重分配操作,并且未将来的字符串扩充预留了空间;当然也可以使用【sdsfree】真正释放sds;

状态【3】:

struct sdshdr{ int len=11; int free=9; char buf[]={‘h’,’e’,’l’,’l’,’o’,’d’,’i’,’s’,’d’,’i’,’s’,’\0′,…}; }; 关于第三点,SDS的buf属性称为字节数组,保存的是二进制数据;同时由于使用len字段来判断字符串是否结束,所以是安全的,不会出现c字符串中以空格作为结尾判断,导致字符串被截断的问题。

有一种缘,放手后成为风景,有一颗心,坚持中方现真诚。

Redis数据结构(一)简单动态字符串

相关文章:

你感兴趣的文章:

标签云: