基於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; }