robj(redisObject)看下源码中的定义:
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
* LFU data (least significant 8 bits frequency
* and most significant 16 bits access time). */
int refcount;
void *ptr;
} robj;
type:(4个位大小) 标识对象的类型 分别有:
#define OBJ_STRING 0 /* 字符串. */
#define OBJ_LIST 1 /* 列表. */
#define OBJ_SET 2 /* 集合. */
#define OBJ_ZSET 3 /* 有序集合. */
#define OBJ_HASH 4 /* 哈希. */
encoding:(4个位大小) 标识robj的ptr的实现类型 分别有:
#define OBJ_ENCODING_RAW 0 /* Raw representation */
#define OBJ_ENCODING_INT 1 /* 整形编码 */
#define OBJ_ENCODING_HT 2 /* 哈希编码 */
#define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */
#define OBJ_ENCODING_LINKEDLIST 4 /* 不再使用双端队列. */
#define OBJ_ENCODING_ZIPLIST 5 /* 压缩列表 */
#define OBJ_ENCODING_INTSET 6 /* 整数集合 */
#define OBJ_ENCODING_SKIPLIST 7 /* 跳跃表 */
#define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
#define OBJ_ENCODING_QUICKLIST 9 /* 快表 */
#define OBJ_ENCODING_STREAM 10 /* Encoded as a radix tree of listpacks */
lru:(24位大小) 内存置换策略,可以参考我这篇文章
refcount:引用计数
ptr:通过encoding字段可知指针的数据结构 然后进行下一步操作
分析创建redisObject相关函数
robj *createObject(int type, void *ptr) 基础的分配内存并初始化各个属性
robj *makeObjectShared(robj *o) 只需要把robj的refcount属性置为OBJ_SHARED_REFCOUNT 即可把对象变成共享对象
robj *createRawStringObject(const char *ptr, size_t len)创建一个编码方式为OBJ_ENCODING_RAW的robj对象 注意该方式用了两次内存申请,意味着ptr跟robj并不是连续的内存空间
robj *createEmbeddedStringObject(const char *ptr, size_t len)创建一个编码方式为OBJ_ENCODING_EMBSTR的robj对象 该方式先申请足够的内存空间 然后进行copy操作把ptr复制进来
robj *createStringObject(const char *ptr, size_t len)创建一个字符串对象,先判断了字符串的长度是否大于OBJ_ENCODING_EMBSTR_SIZE_LIMIT(44)如果大于则创建一个RawStringObject否则创建EmbeddedStringObject
为什么是44呢?因为在64位的机器里面redisObject结构的大小是20byte 20+44 = 64byte正好是jemalloc内存管理器的small_class的一个bin 在(48,64] 区间内的内存申请都会给分配64byte的内存 其实可以选(32,48] ...(64, 80]为啥选(48,64]可能是作者经过实践得出来的结论吧
robj *createStringObjectFromLongLongWithOptions(long long value, int valueobj)把整数转换成string 返回一个共享/非共享的robj 取决于valueobj的值
redis在初始化的时候会保存着10000以下的共享整数string robj