string資料型別的物件編碼有兩種,分別是embstr
和raw
。兩種編碼的區別並不大,embstr
相對於raw
,記憶體空間連續。兩者的資料格式見下圖:
redis的string資料之所以使用embstr
和raw
兩種編碼格式,是為了當乙個string物件的值比較小時,使用乙個連續的記憶體分割槽存放redisobject物件和sdshdr物件,減少記憶體分配和**的消耗。
embstr
編碼的string資料只需要建立分配乙個記憶體空間,用於同時存放redisobject物件和sdshdr物件;而raw
編碼的string資料需要建立兩個記憶體空間分別存放redisobject物件與sdshdr物件,相對於embstr
編碼多了一次記憶體分配和一次記憶體**的消耗。
當乙個string物件的長度達到臨界值時,就會觸發編碼轉換,該臨界值是string值長度:44。
如下測試,當string值的長度不大於44時,通過debug命令輸出該string物件的編碼格式為encoding:embstr
;當string值的長度大於44時,編碼格式則為encoding:raw
。
127.0.0.1:6379> set key1 12345678901234567890123456789012345678901234
ok127.0.0.1:6379> debug object key1
value at:0x7f8428e22080 refcount:1 encoding:embstr serializedlength:21 lru:2200798 lru_seconds_idle:6
127.0.0.1:6379> set key2 123456789012345678901234567890123456789012345
ok127.0.0.1:6379> debug object key2
value at:0x7f8428eb3490 refcount:1 encoding:raw serializedlength:21 lru:2200816 lru_seconds_idle:3
關鍵原始碼如下:
#define obj_encoding_embstr_size_limit 44
robj *
createstringobject
(const
char
*ptr, size_t len)
robj *
tryobjectencoding
(robj *o)..
.}
embstrrobj *
createembeddedstringobject
(const
char
*ptr, size_t len)
else
sh->len = len;
sh->alloc = len;
sh->flags = sds_type_8;
if(ptr == sds_noinit)
sh->buf[len]
='\0'
;else
if(ptr)
else
return o;
}
rawrobj *
createrawstringobject
(const
char
*ptr, size_t len)
robj *
createobject
(int type,
void
*ptr)
else
return o;
}
臨界值44
之所以embstr
和raw
兩種編碼格式的臨界值是44,是因為redis控制乙個string物件的記憶體大小不大於64位元組時為乙個小字串,使用乙個連續空間能夠提高效能。當string物件的記憶體大小大於64位元組時,則認為是乙個大字串,不再適用embstr
編碼格式,而使用raw
編碼。
由圖可見,redisobject物件和sdshdr物件至少需要佔19位元組,64個位元組空間最後留給string值的只有45個位元組。而string末尾需要額外乙個\0
表示字串結束,所以實際上留給string值最多只有44個位元組。
redis的string物件直接通過set
等方法建立時,不會建立冗餘空間,因為大多數情況下建立的string型別不需要進行追加擷取等操作。
擴容規則
通過預先建立冗餘空間,可以減少string資料追加擷取時的記憶體空間分配消耗。
sds sdscatlen
(sds s,
const
void
*t, size_t len)
#define sds_max_prealloc (1024*1024)
sds sdsmakeroomfor
(sds s, size_t addlen)
else
sdssetalloc
(s, newlen)
;return s;
}
原始碼分析之String
先看屬性 底層是char陣列,一目了然 可以看到,value是儲存string的內容的,即當使用string str abc 的時候,本質上,abc 是儲存在乙個char型別的陣列中的。string底層的儲存結構是乙個字元型別的陣列,同樣也是被final修飾,因此一旦這個字元陣列被建立後,value...
golang 原始碼分析之string
stringgo 語言中的字串其實是乙個唯讀的位元組陣列string 對應的結構 type stringheader struct type stringstruct struct 字串拼接 concatstrings runtime concatstrings func concatstrings...
redis原始碼之dict
大家都知道redis預設是16個db,但是這些db底層的設計結構是什麼樣的呢?我們來簡單的看一下原始碼,重要的字段都有所注釋 typedef struct redisdb redisdb redis中的所有kv都是存放在dict中的,dict型別在redis中非常重要。字典disc的資料結構如下 t...