基于redis5.0的版本。
字符串编码:字符串对象的编码能够是int,raw或者embstr。git
raw就是redisObject+sds
,即redisObject
的ptr
指针指向一个sds
对象。github
// object.c define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44 robj *createStringObject(const char *ptr, size_t len) { if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT) return createEmbeddedStringObject(ptr,len); else return createRawStringObject(ptr,len); } robj *createRawStringObject(const char *ptr, size_t len) { return createObject(OBJ_STRING, sdsnewlen(ptr,len)); } /* Create a string object with encoding OBJ_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(const char *ptr, size_t len) { robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr8)+len+1); // 申请连续的空间 struct sdshdr8 *sh = (void*)(o+1); o->type = OBJ_STRING; o->encoding = OBJ_ENCODING_EMBSTR; o->ptr = sh+1; o->refcount = 1; if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) { o->lru = (LFUGetTimeInMinutes()<<8) | LFU_INIT_VAL; } else { o->lru = LRU_CLOCK(); } sh->len = len; sh->alloc = len; sh->flags = SDS_TYPE_8; if (ptr == SDS_NOINIT) sh->buf[len] = '\0'; else if (ptr) { memcpy(sh->buf,ptr,len); sh->buf[len] = '\0'; } else { memset(sh->buf,0,len+1); } return o; }
若是字符串对象保存的是一个字符串值,而且这个字符粗值的长度小于等于44
字节(44这个值并不会一直保持不变,例如redis3.2版本以前是39),则使用embstr
编码,embstr即embedded string,“嵌入式的字符串,将SDS结构体嵌入RedisObject对象中”
,是专门用于保存短字符串的一种编码方式,与raw的差异在于,raw会调用两次内存分配函数来建立redisObject结构和sdshdr结构,而embstr编码则经过调用一次内存分配函数来分配一块连续的空间,空间内一次包含了redisObject和sdshdr两个结构。
embstr有如下好处:redis
embstr的缺点:缓存
redis> SET msg hello OK redis> OBJECT ENCODING msg embstr redis> DEBUG OBJECT msg Value at:0x7fd74ecac8a0 refcount:1 encoding:embstr serializedlength:6 lru:815344 lru_seconds_idle:14 redis> APPEND msg world 10 redis> OBJECT ENCODING msg raw redis> DEBUG OBJECT msg Value at:0x7fd76445d0b0 refcount:1 encoding:raw serializedlength:11 lru:815482 lru_seconds_idle:26
sdshdr=len 1byte + alloc 1byte + flag 1byte + '0' 1byte + buf长度。(3.2以前的版本)服务器
从2.4版本开始,redis开始使用jemalloc内存分配器。能够简单理解,jemalloc不是一个一个字节来申请和分配的,会分配8,16,32,64等字节的内存(如须要12个字节,就会分配16个字节)。embstr最小为16+8+1=25,因此最小分配64字节。当字符数小于39时,都会分配64字节。这个默认39就是这样来的。app
3.2版本以前是39,3.2开始是44,函数
若是一个字符串对象保存的是整数,而且这个整数值能够用long类型来标识(不超过long的范围),这时候字符串对象redisobject的指针将直接保存long数值(将void *转换成long)。优化
// server.h define OBJ_SHARED_INTEGERS 10000 // object.c robj *createStringObjectFromLongLongWithOptions(long long value, int valueobj) { robj *o; if (server.maxmemory == 0 || !(server.maxmemory_policy & MAXMEMORY_FLAG_NO_SHARED_INTEGERS)) { /* If the maxmemory policy permits, we can still return shared integers * even if valueobj is true. */ valueobj = 0; } if (value >= 0 && value < OBJ_SHARED_INTEGERS && valueobj == 0) { // 10000之内直接用共享的对象 incrRefCount(shared.integers[value]); o = shared.integers[value]; } else { if (value >= LONG_MIN && value <= LONG_MAX) { o = createObject(OBJ_STRING, NULL); o->encoding = OBJ_ENCODING_INT; o->ptr = (void*)((long)value); // 直接将long值转为指针地址存储 } else { o = createObject(OBJ_STRING,sdsfromlonglong(value)); } } return o; }