redis源码之:字符串SDS

先来看看redis中字符串sds的大致结构:
在这里插入图片描述
debug所用demo如下

#include "src/server.h"

void testSDS();
void testAlign();
int main(int argc, char **argv) {
//    testAlign();
    testSDS();
}
/**
 * __attribute__ ((__packed__))取消对齐
 *  __attribute__((aligned(4)))指定对齐大小,这里只整个结构体的对齐,当结构体内各成员间对齐后,没有达到aligned的值,则补齐
 *  https://code84.com/787223.html
 *  #pragma pack(8)  //设置结构体内成员间对齐大小,pack中参数大小与成员类型最长的值,取小值
 *  如:结构体中最大的类型是int四个字节,那么设置pragma pack(8),实际结构体内还是按4字节来对齐,此时,c1一个字节后会补齐三个字节
 *  假如c1,c2相邻,这两个成员则合并两个字节,然后补齐两个字节,然后再到下一个成员
 *
 */
#pragma pack(2)
typedef struct __attribute__((aligned(8)))/*__attribute__ ((__packed__))*/
{
    char c1;//1字节 0   对齐:0
    int i;  //4字节 1        4
    char c2;//     5        8
    long l0;
    char arr[];
} test_0;

void testSDS() {
    sds s0 = sdsnew("ddddddd");//"Xhello sds \n"
    sds s00 = sdscat(s0,"catt");//预分配机制,减少分配次数,新增后总长度 len+addlen < 1MB,则按新长度的两倍扩容,新增后总长度 len+addlen > 1MB,则按新长度加上 1MB 扩容
//    s = s-1;
    size_t size1 = sizeof(s0);
//    sdsfree(s00);//释放sds占用的空间
//    sdsclear(s00); //只是将字符串的结束标识设置到flag后,将len设置为0
    sdsRemoveFreeSpace(s00);//将预分配的空间收缩

    //"\001hello sds dddddddddddddddddddddddddddddffffffffffffffffffffffffffdddddddddddddfdfddd"
    sds s2 = sdsnew("hello sds dddddddddddddddddddddddddddddffffffffffffffffffffffffffdddddddddddddfdfddd");
    sds s22 = sdscat(s2,"catt");
}

void testAlign(){
    //内存对齐测试
    test_0 a;
    test_0 *aa = &a;
    printf("c1 -> %d, i -> %d, c2 -> %d,l0-> %d,arr->%d\n",
           offsetof(test_0,c1),
           offsetof(test_0,i),
           offsetof(test_0,c2),
           offsetof(test_0,l0),
           offsetof(test_0,arr)
    );
    int size = sizeof(a);
    printf("c1 -> %d, i -> %d, c2 -> %d,l0-> %d,a->%d\n",
           (unsigned int)(void *)&a.c1 /*- (unsigned int)(void *)&a*/,
           (unsigned int)(void *)&a.i/*- (unsigned int)(void *)&a*/,
           (unsigned int)(void *)&a.c2 /*- (unsigned int)(void *)&a*/,
           (unsigned int)(void *)&a.l0 /*- (unsigned int)(void *)&a*/,
           (unsigned int)(void *)&a);
    printf("c1 -> %d, i -> %d, c2 -> %d\n",
           (unsigned int)(void *)&a.c1 - (unsigned int)(void *)&a,
           (unsigned int)(void *)&a.i- (unsigned int)(void *)&a,
           (unsigned int)(void *)&a.c2 - (unsigned int)(void *)&a);

    //柔性数组测试
    test_0 *softp = malloc(sizeof(test_0)+sizeof(int)*4);
    test_0 soft = *softp;
    int sizes = sizeof(soft);//sizeof不会列出柔性数组占用大小
    soft.arr[0] = 'h';
    int sizes1 = sizeof(soft);

}

这里我们重点关注几个方法:sdsnew,sdscat,sdsRemoveFreeSpace,sdsfree,设计新建,扩容,收缩,释放。
一、sds创建
在这里插入图片描述

redis根据不同长度字符串,使用不同结构体头部尽可能压缩头部占用空间,同时使用__attribute__ ((packed))紧密排列结构体内成员,以节省内存空间。结构体中存储了长度表示,直接根据长度截取数据,避免原始字符串从头开始遍历到结束符的操作。同时SDS也是为兼容C的原始字符串,采用以\0结尾。创建sds的时候返回的不是sdshdr结构体,而是一个char指针,为何要这样骚操作,一个是为了兼容原始字符串,另一个是为了统一处理不同类型的sds。sds不仅可以存储字符串数据,还可以存储二进制数据,如图片,文本等。

二、SDS扩容
在这里插入图片描述

在sdshdrX类型不变的扩容时,使用realloc()方法扩容,该方法会尝试在原来的地址上扩展,如果可扩展的连续空间不足,则分配新的空间并复制旧的数据,并释放原来的空间,可考虑自行重新申请内存再把原本的数据复制过去,当然这种方式效率稍低一点点。

三、空间释放
1、sdsclear()
只是将字符串的结束标识设置到flag后,将len设置为0,申请的内存空间并没释放
在这里插入图片描述
将s指针往后移一位,仍然可以看到原本的字符串内容:
在这里插入图片描述
2、sdsfree()
在这里插入图片描述
3、sdsRemoveFreeSpace()
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值