第八章 对象

Redis中的对象:

  • 字符串对象
  • 列表对象——压缩列表或双端链表
  • 哈希对象——压缩列表或字典
  • 集合对象——整数集合或字典
  • 有序集合对象——压缩列表或跳表+字典

每个对象针对不同的使用场景选择底层实现,并使用引用计数器决定对象的回收,某些条件下可以通过引用计数器实现共享。

8.1 对象的类型和编码

  Redis中的键和值都是对象,键固定是字符串对象,称某某键指的是值对象。譬如列表键,即值是列表对象。redisObject的结构和对象类型编码内存回收共享对象都有关系,一个对象内存占用 4bit+4bit+24bit+4byte+8byte=16byte

typedef struct redisObject{
    //对象类型
    unsigned type:4bit;
    //实现对象的编码方式
    unsigned encoding:4bit;
    //指向底层实现数据结构的指针,在64位系统中,一个指针8字节 
    void *ptr:8byte;
    ....
    //引用计数,int占用4字节
    int refcount:4byte; 
    //最后一次被命令程序访问的时间,在2.6版本是22bit,在4.0版本是24bit
    unsigned lru:22bit; 

}

8.2 字符串对象

  编码方式:

  • int编码:字符串对象保存的值是整数值(long)
  • raw编码:字符串对象保存的值是字符串,并且长度大于39字节,使用SDS实现
  • embstr编码:针对段字符串的优化,减少分配和释放需要的内存分配次数  

  raw编码和embstr编码也可以保存浮点数

  字符串对象大小不能超过512M

  8.2.1 编码的转换

  int编码的值被修改成字符串、embstr编码的值一旦被修改(例如APPEND操作),都会被转换成raw编码方式。

 

8.3 列表对象

  redis> RPUSH numbers 1 "three" 5

  编码方式:

  • ziplist编码:底层使用压缩列表实现

  

  • linkedist编码:使用双端列表实现

  

  当列表对象保存的所有字符串元素的长度小于64字节,且对象保存的元素数量小于512个时,使用ziplist编码,否则使用linkedlist编码

8.4 哈希对象

  编码方式:

  • ziplist编码:使用压缩列表实现。当有新键值对插入时,先将键的压缩列表节点推入列表的尾部,再将值的压缩列表节点推入列表的尾部。
  • hashtable编码:使用字典实现。

    当哈希对象保存的所有键值对的字符串都小于64字节,并且键值对的数量小于512个,使用ziplist编码,否则使用hashtable编码

8.5 集合对象

  redis>SADD numbers 1 3 5

  编码方式:

  • intset编码:使用整数集合实现。
  • hashtable编码:使用字典实现。字典的每个键都是字符串对象,保存了一个集合的值,字典的值全部设置为NULL。

  当保存的集合的元素都是整数,并且总数不超过512个时,使用intset编码,否则使用hashtable编码

8.6 有序集合对象

  编码方式:

  • ziplist编码:每个元素使用两个压缩列表节点表示,第一个存放元素的值,第二个存放元素的分值。元素按照分值大小从小到大排序,分值越大越靠近表尾。
  • skiplist编码:使用跳表+字典实现。

  在跳表的实现中,每个节点的object保存了元素的值,score保存了分值。使用ZRANK和ZRANGE等范围操作可以有效的使用跳表排序的特性。

  在字典的实现中,字典键存放元素的值,字典值存放元素的分数。查找每个元素的分值的复杂度是常量级。

  同时使用跳表和字典实现,会用指针来共享元素的成员和分值,所以不会造成额外内存的浪费。还能结合二者的优势。

  当保存的集合的元素数量小于128个,而且所有元素的长度都小于64字节时,使用ziplist编码,否则使用skiplist实现。

8.7 类型检查和命令多态

  • 类型检查:不同的命令针对不同的对象,Redis在执行特定命令时,会通过对象中的type属性检查输入键的类型是否正确。
  • 多态命令:同一个命令的目标对象,底层的实现不同,调用的API也不同,Redis通过encoding属性得知具体的底层实现,调用不同的API。

8.8 内存回收

  对象的refcount属性记录了引用关系

  • 创建新对象时,引用计数器初始化成1
  • 当对象被一个新的程序使用时,计数器值+1
  • 当对象不再被某个程序使用时,计数器值-1
  • 当对象的引用计数器值变成0,对象占用的内存被释放

8.9 对象共享

  当一个对象被多个程序使用时,譬如键A的值对象和键B的值对象相同时,只会创建一个对象,A和B的值对象都指向该对象,同时该对象的引用计数器记为2。受到CPU时间的限制,Redis只对包含整数值的字符串对象进行共享。目前Redis会共享0~9999的字符串对象。

8.10 对象的空转时常

  对象的lru属性,记录了对象最后一次被命令程序访问的时间。OBJECT IDLETIME命令可以打印出给定键的lru属性,并且不会更改lru属性。

 

posted @ 2021-02-23 22:55  walker993  阅读(26)  评论(0编辑  收藏  举报