redis对象编码源码阅读——字符串编码与创建

本文深入探讨Redis中字符串对象的编码方式,包括embstr和raw编码的区别,以及这两种编码在创建、内存管理和缓存效率上的差异。通过源码阅读,揭示字符串创建过程中的细节,如额外分配的空间和对象结构的变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

redis对象编码源码阅读——字符串编码与创建

1. 字符串的编码

类型编码对象
REDIS_STRINGREDIS_ENCODING_INT使用整数值实现的字符串对象
REDIS_STRINGREDIS_ENCODING_EMBSTR使用embstr编码的简单动态字符串实现的字符串对象
REDIS_STRINGREDIS_ENCODING_RAW使用简单动态字符串实现的字符串对象

摘自《Redis设计与实现》第63页

2. 创建字符串对象

在创建字符串对象的时候,有两种创建方式,一种是EMBSTR,一种是RAW.

REDIS_ENCODING_EMBSTR_SIZE_LIMIT是一个比较小的值39。所以两者最大的区别就是长度。EMBSTR表示短字符串,RAW表示长字符串。

robj *createStringObject(char *ptr, size_t len) {
    if (len <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT)
        return createEmbeddedStringObject(ptr,len);
    else
        return createRawStringObject(ptr,len);
}

3. EMBSTR字符串创建

在分配空间的时候,不仅分配了robj的空间,还额外分配了sdshdr的空间,并把o->ptr直接指向了sdshdr对象。

/* Create a string object with encoding REDIS_ENCODING_EMBSTR, that is
 * an object where the sds string is actually an unmodifiable string
 * allocated in the same chunk as the object itself. */
robj *createEmbeddedStringObject(char *ptr, size_t len) {
    robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr)+len+1);
    // 正好指向 sdshdr 数据结构
    struct sdshdr *sh = (void*)(o+1);

    o->type = REDIS_STRING;
    o->encoding = REDIS_ENCODING_EMBSTR;
    // 正好指向 sdshdr 的字符串
    o->ptr = sh+1;
    o->refcount = 1;
    o->lru = LRU_CLOCK();

    // len: 表示总长度
    // free: 表示剩余长度
    sh->len = len;
    sh->free = 0;
    if (ptr) {
        memcpy(sh->buf,ptr,len);
        sh->buf[len] = '\0';
    } else {
        memset(sh->buf,0,len+1);
    }
    return o;
}

4. RAW字符串创建

无编码字符串只分配了robj对象的空间,并直接把o->ptr指向了字符串对象char*

这里和《Redis设计与实现》65页的图8-2,存储结构矛盾了。我认为这里创建的RAW对象之后的结构肯定还是会变化的,之后会再次申请sdshdr的空间,与书上一样。

/* Create a string object with encoding REDIS_ENCODING_RAW, that is a plain
 * string object where o->ptr points to a proper sds string. */
robj *createRawStringObject(char *ptr, size_t len) {
    return createObject(REDIS_STRING,sdsnewlen(ptr,len));
}
robj *createObject(int type, void *ptr) {
    robj *o = zmalloc(sizeof(*o));
    o->type = type;
    o->encoding = REDIS_ENCODING_RAW;
    o->ptr = ptr;
    o->refcount = 1;

    /* Set the LRU to the current lruclock (minutes resolution). */
    o->lru = LRU_CLOCK();
    return o;
}

5. EMBSTR编码的好处

  • embstr编码将创建字符串对象所需的内存分配次数从raw编码的两次降低为一次

  • 释放embstr编码的字符串对象只需要调用一次内存释放函数,而释放raw编码的字符串对象需要调用两次内存释放函数

  • 因为embstr编码的字符串对象的所有数据都保存在一块连续的内存里面,所以这种编码的字符串对象比起raw编码的字符串对象能够更好的利用缓存带来的优势

以上摘自《Redis设计与实现》第65页,详情见65页

  • EMBSTR编码字符串的长度可能非常长,也可能比较短,跨度是非常大的,所以每次(我猜测)字符串内容改变的时候,都需要判断字符串是不是需要释放多余的空间,如果可以的话还可以换成其他编码。即调用tryObjectEncoding函数

  • 而在tryObjectEncoding函数中,如果要释放多余空间的话,函数会先释放之前的char*空间,再申请新的空间,这也是RAWEMBSTR的区别

Redis字符串类型内部编码剖析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值