問題來了
今天在看書籍《Redis設計與實現》的時候,在8.2字符串對象里面寫到
- 如果字符串對象保存的是一個字符串值, 並且這個字符串值的長度大於 39 字節, 那么字符串對象將使用一個簡單動態字符串(SDS)來保存這個字符串值, 並將對象的編碼設置為 raw 。
- 如果字符串對象保存的是一個字符串值, 並且這個字符串值的長度小於等於 39 字節, 那么字符串對象將使用 embstr 編碼的方式來保存這個字符串值。
自己本地實驗的時候,就算字符小於39,也是raw類型的,不知道為什么。
原來是版本的原因
去查看源碼。才發現這個和redis的版本有關系。查看redis-3.0和最新的版本的object.c文件,可以發現在創建StringObject的時候,會和REIDS_ENCODING_EMBSTR_SIZE_LIMIT比較,這個的默認值是39。查看一下redis-2.8版本的源碼,並沒有發現比較,而是直接創建了。
所以我猜測這個embstr編碼是3.0以上版本才出現的。
39哪來的
至於為什么是39,這個講起來就比較復雜了,我就慢點說。
embstr是一塊連續的內存區域,由redisObject和sdshdr組成。其中redisObject占16個字節,當buf內的字符串長度是39時,sdshdr的大小為8+8+39+1=56,那一個字節是'\0'。加起來剛好64。是不是發現了什么?
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
int refcount;
void *ptr;
} robj;
struct sdshdr {
unsigned int len;
unsigned int free;
char buf[];
};
從2.4版本開始,redis開始使用jemalloc內存分配器。這個比glibc的malloc要好不少,還省內存。在這里可以簡單理解,jemalloc會分配8,16,32,64等字節的內存。embstr最小為16+8+8+1=33,所以最小分配64字節。當字符數小於39時,都會分配64字節。
這個默認39就是這樣來的