Redis 字符串详解[勘误](附带思维导图)| 小册免费学

400 阅读3分钟

Redis 字符串详解.png

底层实现——结构体

Redis 中的字符串是可以修改的字符串,在内存中它是以字节数组的形式存在的。Redis 中的字符串是可以修改的字符串,在内存中它是以字节数组的形式存在的。

struct SDS<T> {
  T capacity; // 数组容量
  T len; // 数组长度
  byte flags; // 特殊标识位,不理睬它
  byte[] content; // 数组内容
}

这里代码作者应该是想表达泛型,但如果底层是用字节数组时,其实根本是不必要的,对于一定是整数的数组容量和长度设置泛型也没什么意义啊。。,而且SDS本身作为一个字符串,用T[] content也未必合适

真的是这样吗

image.png

字符串的扩容

初次分配,len和capacity一样,但append之后就会触发扩容

APPEND 可以为一系列定长(fixed-size)数据(sample)提供一种紧凑的表示方式,通常称之为时间序列。

/**
*** s 字符串 
*** t 将追加到字符串的内容
*** len 追加字符串的长度

**/
sds sdscatlen(sds s, const void *t, size_t len) {
    size_t curlen = sdslen(s);  // 原字符串长度

    // 按需调整空间,如果 capacity 不够容纳追加的内容,就会重新分配字节数组并复制原字符串的内容到新数组中
    s = sdsMakeRoomFor(s,len);
    if (s == NULL) return NULL; // 内存不足
    memcpy(s+curlen, t, len);  // 追加目标字符串的内容到字节数组中
    sdssetlen(s, curlen+len); // 设置追加后的新长度值
    s[curlen+len] = '\0'; // 让字符串以\0 结尾,便于调试打印,还可以直接使用 glibc 的字符串函数进行操作
    return s;
}

size_t而不是int:因为当字符串比较短时,len 和 capacity 可以使用 byte 和 short 来表示,Redis 为了对内存做极致的优化,不同长度的字符串使用不同的结构体来表示。

范型是作者抽象出来的,实际Redis源码中是动态的从无符号的char/short/int/longlong中选择使用

Redis 规定字符串的长度不得超过 512M 字节。创建字符串时 len 和 capacity 一样长,不会多分配冗余空间,这是因为绝大多数场景下我们不会使用 append 操作来修改字符串。

embstr vs raw(两种存储方式)

Redis 的字符串有两种存储方式,在长度特别短时,使用 emb 形式存储 (embedded),当长度超过 44 时,使用 raw 形式存储。

Redis 对象头结构体

所有的 Redis 对象都有下面的这个结构头:

struct RedisObject {
    int4 type; // 4bits
    int4 encoding; // 4bits
    int24 lru; // 24bits
    int32 refcount; // 4bytes
    void *ptr; // 8bytes,64-bit system 对象内容 (body) 的具体存储位置
} robj; 
// 共 4*2/8 + 24/8 + 32/8 + 64/8 = 16 

当字符串较小的时候,容量和长度可以用1字节表示,即3+ (content).size + 对象头(16)

而内存分配器 jemalloc/tcmalloc 等分配内存大小的单位都是 2、4、8、16、32、64 等等,为了能容纳一个完整的 embstr 对象,jemalloc 最少会分配 32 字节的空间,如果字符串再稍微长一点,那就是 64 字节的空间。

再长的话就是raw,不同于emb将SDS和对象头放在一起,raw将字符数组独立content了出来

勘误

append后,存储方式变化

redis版本4.0.14,无论初始set字符串长度多短,只要append操作,无论追加字符串多短,embstr就会变成raw类型,

SDS结构

image.png

struct sdshdr{
//记录buf数组中已使用字节的数量
//等于SDS所保存的字符串长度
int len;

//记录buf数组中未使用字节的数量
int free;

//字节数组,用于保存字符串
char buf[];
}

文章末尾请带上以下文字及链接:本文正在参与「掘金小册免费学啦!」活动, 点击查看活动详情