美文网首页
搞懂Redis(二)-1:String数据结构

搞懂Redis(二)-1:String数据结构

作者: 高19 | 来源:发表于2022-04-13 17:37 被阅读0次

    String类型的转换顺序

    • 当保存的值为整数且值的大小不超过long的范围,使用整数存储
    • 当字符串长度不超过44字节时,使用embstr编码
      (只实现一次分配内存空间,只允许读,若修改数据,就会转成raw编码)
    • 大于44字符时,用raw编码

    sds

    embstr和raw都为sds编码.

    Redis是用C语言开发的,为什么不用C语言里面的字符串,而使用sds结构体呢?

    1. 低复杂度获取字符串长度; 有len存在,可以直接查出字符串长度,复杂度O(1);如果用C语言字符串,需要遍历整个字符串,复杂度为O(n)
    2. 避免缓冲区溢出; 进行两个字符串拼接C语言可使用strcat函数,但没有足够的内存空间.就会造成缓冲区溢出.但用sds合并时会用len检查内存空间是否满足需求,不满足再进行空间扩展,不会造成缓冲区溢出.
    3. 减少修改字符串的内存重新分配次数; C语言字符串不记录字符串长度,如果要修改字符串,要重新分配内存,不分配可能会造成内存缓冲区泄露.

    Redis的sds实现了空间预分配和惰性空间释放两种策略

    • 空间预分配
    1. 如果sds修改后,len长度<1mb.则会分配与len相同的未使用空间. 例 修改后字符串长度为100字节,那么会分配100字节的未使用空间,最终长度为 100+100+1(空字符\0)
    2. 如果长度≥1mb,每次分配1mb未使用空间
    • 惰性空间释放
      对字符串进行缩短操作时,程序不立即使用内存重新分配来回收缩短后多余的字节,而是使用free属性将这些字节数量记录下来,等待后续使用(也可手动触发字符串缩短)

    二进制安全:
    C语言字符串是用空字符来判断结束,但对于一些二进制文件(如图片等),其内容包含空字符串,因此C语言字符串无法正确存取.而所有的sds的api都是以二进制的方式来处理buf里面的元素,并且sds是以len长度来判断字符串是否结束.

    遵从空字符结束的惯例,这样可以重用C语音库<string.h>的一部分函数

    为什么小于44字节的用embstr呢?

    再看一下rejectObject和sds定义的结构(短字符串的embstr用最小的sdshdr8)

    
    typedef struct redisObject {
        // 类型 4bits
        unsigned type:4;
        // 编码方式 4bits
        unsigned encoding:4;
        // LRU 时间(相对于 server.lruclock) 24bits
        unsigned lru:22;
        // 引用计数 Redis里面的数据可以通过引用计数进行共享 32bits
        int refcount;
        // 指向对象的值 64-bit
        void *ptr;
    } robj;
    
    
    struct __attribute__ ((__packed__)) sdshdr8 {
        uint8_t len; /* used */
        uint8_t alloc; /* excluding the header and null terminator */
        unsigned char flags; /* 3 lsb of type, 5 unused bits */
        char buf[];
    };
    

    RedisObject的占用空间
    4+4+24+32+64 = 128bits = 16字节
    sdsdr8占用空间
    1(uint8_t) + 1(uint8_t)+ 1 (unsigned char)+ 1(buf[]中结尾的'\0'字符)= 4字节
    初始最小分配为64字节,所以只分配一次空间的embstr最大为 64 - 16- 4 = 44字节

    相关文章

      网友评论

          本文标题:搞懂Redis(二)-1:String数据结构

          本文链接:https://www.haomeiwen.com/subject/vvjasrtx.html