redis数据结构——对象

redis中的string、hash、list、set、sorted set 都是对象。这五种对象分别由上几篇说到的数据结构实现。

与java类似的,在java中有object作为所有对象的基类,指代一切对象;redis中也有redisObject作为以上五种对象的基类。

以下是redisObject的结构

typedef struct redisObject {
    unsigned type:4; /* 类型 */
    unsigned encoding:4; /* 编码 */
    unsigned lru:LRU_BITS; /* lru时间(相对于全局lru_clock) */
    int refcount; /* 引用计数 */
    void *ptr; /* 指向底层实现的数据结构的指针 */
} robj;

其中type属性记录了对象的类型,以上五种类型分别用不同的常量表示:

类型常量 对象名称
OBJ_STRING 0 string
OBJ_LIST 1 list
OBJ_SET 2 set
OBJ_ZSET 3 sorted set
OBJ_HASH 4 hash

例如,我们使用TYPE命令查看key所对应的value的类型:


encoding属性决定了ptr指针指向哪一种底层实现,我们还是以上图的K-V为例,使用OBJECT ENCODING命令查看value对象的编码。下图输出表示键msg的值的数据结构是embstr编码的SDS

以下是各种数据结构和对应的encoding常量

#define OBJ_ENCODING_RAW 0     /* SDS */
#define OBJ_ENCODING_INT 1     /* 整数 */
#define OBJ_ENCODING_HT 2      /* 字典 */
#define OBJ_ENCODING_ZIPMAP 3  /* 压缩map */
#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  /* embstr编码的SDS */
#define OBJ_ENCODING_QUICKLIST 9 /* 快速链表 */


5种对象,每一种至少使用了2种不同的编码。


refcount引用计数,有两个作用:

1、是用来判断是否需要内存回收的。在创建新的对象的时候,refcount=1;当对象被新的对象使用时,refcount++,当它不再被一个程序使用时,refcount--。直到refcount=0,释放对象占用的内存。

2、用于对包含整数值的SDS对象共享。例如 set A 100 ; set B 100 这两个命令。这时redis会让value的指针指向同一个值对象,且refcount++。但是,redis不对包含字符串的SDS对象共享,是因为在对对象进行共享时,会校验共享对象和目标对象是否一致,包含整数值的SDS对象的验证操作时间复杂度是O(1),但是包含字符串的SDS对象的验证操作时间复杂度是O(N),如果共享对象是列表对象或者hash对象,那么验证操作时间复杂度是O(N^2),这样,虽然共享对象能够节约空间,但是这些情况下会消耗更多的性能。


最后说说lru属性。它记录了对象最后一次被命令程序访问的时间。具体内容其实可以参考LRU算法。lru记录的时间距离当前时间的时间差被称为空转时长,空转时长越长,也就是说这个对象越久没有被程序访问过,那么当内存达到maxmemory设置的最大内存值的,会首先释放这个对象,回收内存。

你可能感兴趣的:(redis源码学习)