redis 的 SDS 内存分配
首先最基础的就是一个 redis 对象
typedef struct Object {
unsigned type: 4;
unsigned encodings:4;
void* ptr;
} robj;
其中的ptr 是一个指向底层value的指针, 区别就在于这个执政指向的值是和object 一起创建的, 还是单独创建的, 也就是一个创建2次,一个创建1次:
/*
44是因为 N = 64 - 16(redisObject) - 3(sdshr8) - 1(\0), N = 44 字节。
那么为什么是64减呢,为什么不是别的,因为在目前的x86体系下,一般的缓存行大小是64字节
*/
#define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44
robj *createStringObject(const char *ptr, size_t len) {
//创建嵌入式字符串,字符串长度小于等于44字节
if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT)
return createEmbeddedStringObject(ptr, len);
//创建普通字符串,字符串长度大于44字节
else
return createRawStringObject(ptr,len);
}
- 当于44的时候使用
createEmbeddedStringObject
, 创建一个robj+sdshdr8
robj* createEmbeddedStringObject(char* ptr, size_t len)
{
//创建的是robj+sdshdr8
//|--robj--|--sdshdr8--|
robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr8)+len+1);
struct sdshdr8 *sh = (void*)(o+1);
o->ptr = sh;
//直接拷贝
memcpy(sh->buf, ptr, len);
sh->buf[len] = '\0';
}
- 当大于44的时候使用需要分配2次:
//>44, 需要分配两次内存
robj *createRawStringObject(const char *ptr, size_t len) {
return createObject(OBJ_STRING, sdsnewlen(ptr,len));
}
robj *createObject(int type, void *ptr) {
//给redisObject结构体分配空间
robj *o = zmalloc(sizeof(*o));
//设置redisObject的类型
o->type = type;
//设置redisObject的编码类型,此处是OBJ_ENCODING_RAW,表示常规的SDS
o->encoding = OBJ_ENCODING_RAW;
//直接将传入的指针赋值给redisObject中的指针。
o->ptr = ptr;
o->refcount = 1;
…
return o;
}