Redis对象

Redis对象

Redis系统包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象。

Redis还实现了基于引用计数的内存回收机制,通过引用计数实现了对象共享机制,在这机制在,通过让多个数据库键共享同一个对象来节约内存。

Redis的类型与编码

类型

       对象的type属性记录了对象的类型

编码和底层实现

REDIS_STRING

  1. REDIS_ENCODING_INT:使用整数值实现的字符串对象。
  2. REDIS_ENCODING_EMBSTR:使用embstr编码的简单动态字符串实现字符串对象。
  3. REDIS_ENCODING_RAW:使用简单动态字符串实现字符串对象。

REDIS_LIST

  1. REDIS_ENCODING_ZIPLIST:使用压缩列表实现列表对象。
  2. REDIS_ENCODING_LINKEDLIST:使用双端链表实现列表对象。

REDIS_HASH

  1. REDIS_ENCODING_ZIPLIST:使用压缩列表实现哈希对象。
  2. REDIS_ENCODING_HT(HASHTABLE):使用字典实现哈希对象。

REDIS_SET

  1. REDIS_ENCODING_INTSET:使用整数集合实现集合对象。
  2. REDIS_ENCODING_HT:使用字典实现集合对象。

REDIS_ZSET

  1. REDIS_ENCODING_ZIPLIST:使用压缩列表实现有序集合对象。
  2. REDIS_ENCODING_SKIPLIST:使用跳跃表事项有序集合对象。

Redis可以根据不同的使用场景来为一个对象选择不同的编码。

字符串对象

字符串对象的编码可以是 int、embstr或raw。

  1. 字符串保存的是一个整数值并且这个整数值可以用long类型表示,那么编码为int;
  2. 字符串长度小于等于39字节,则编码为embstr;
  3. 字符串长度大于39字节,则编码为raw;

Embstr和raw的区别

Embstr编码是专门用于保存较短字符串的一种优化编码方式,这种编码方式和raw编码一样,都使用redisObject结构和sdshdr结构来保存字符串对象;

但raw编码会调用两次内存分配函数来分别创建RedisObject和sdshdr结构,而ebmstr编码则通过调用一次内存分配函数来分配一块连续的空间,空间依次包括RedisObject和sdshdr两个结构。

编码的转换

       Redis没有为embstr编码的字符串实现任何相应的修改程序,embstr编码的字符串在对象执行修改命令之后,总会变成一个raw编码的字符串对象。

列表对象 List

       列表对象的编码可以是ziplist或者linkedlist

编码的转换

       当列表对象可以同时满足以下两个条件时,列表对象使用ziplist编码:

  1. 列表对象保存的所有字符串元素的长度都小于64字节;
  2. 列表对象保存的元素数量小于512个;

不满足其中一个都会将列表对象的编码转换为linkedlist编码。

哈希对象 Hash

哈希对象的编码可以是ziplist或者hashtable

ziplist编码

       使用ziplist编码(压缩列表)的哈希对象,在新增键值对时,程序会先将保存了键的压缩列表节点推入到压缩列表表尾,然后再将保存了值的压缩列表节点推入到压缩列表表尾;因此:

  1. 保存了同一键值对的两个节点总是紧挨在一起,保存键的节点在前,保存值的节点在后;
  2. 先添加的键值对先表头方向,后添加的键值对则在表尾方向;

Hashtable编码

       Hashtable编码的哈希对象使用字典作为底层实现,哈希对象中的每个键值对都使用一个字典键值对来保存:

  1. 字典的每个键都是一个字符串对象,对象中保存了键值对的键;
  2. 字典的每个值都是一个字符串对象,对象中保存了键值对的值;

编码的转换

       当哈希对象同时满足以下两个条件时,哈希对象使用ziplist编码:

  1. 哈希对象保存的所有键值对的键和值的字符串长度都小于64字节;
  2. 哈希对象保存的键值对数量小于512个

不同时满足这两个条件时,哈希对象则使用hashtable编码实现;

集合对象 Set

集合对象的编码可以是intset或hashtable;

Intset编码

Intset编码的集合对象使用整数集合作为底层实现,集合对象包含的所有元素都被保存在整数集合里面。

Hashtable编码

Hashtable编码的集合对象使用字典作为底层实现,字典的每个键都是一个字符串对象,每个字符串对象包含了一个集合元素,而字典的值则全被设置为null;

编码的转换

       当集合对象可以同时满足以下两个条件时,对象使用intset编码:

  1. 集合对象保存的所有元素都是整数值;
  2. 集合对象保存的元素数量不超过512个;

不能同时满足这两个条件的集合对象需要使用hashtable编码。

有序集合对象

       有序集合的编码可以是ziplist或者skiplist;

Ziplist编码

       Ziplist编码实现的有序集合对象使用压缩列表作为底层实现,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员(member),第二元素来保存元素的分值(score);

       压缩列表内的集合元素按分值从小到大进行排序,分值较小的元素被放置在靠近表头的位置,而分值较大的元素则放置在靠近表尾的位置;

Skiplist编码

       Skiplist编码的有序集合使用zset结构作为底层实现,一个zset结构同时包含一个字典和一个跳跃表;

typedef struct zset {

       zskiplist *zsl;

       dict *dict;

}

       Zset结构中的zsl跳跃表按分值从小到大保存了所有集合元素,每个跳跃表节点都保存了一个集合元素:跳跃表节点的Object属性保存了元素的成员,而跳跃表节点score属性则保存了元素的分值。

Zset结构中的dict字典为有序集合创建了一个成员到分值的映射,字典中的每个键值对都保存了一个集合元素:字典的键保存了元素的成员,而字典的值则保存了元素的分值;

编码的转换

       当有序集合对象可以同时满足以下两个条件时,对象使用ziplist编码:

  1. 有序集合保存的元素数量小于128个;
  2. 有序集合保存的所有元素成员的长度都小于64字节;

不能满足以上两个条件的有序集合对象将使用skiplist编码。

Redis对象内存回收

       因为C语言不具备自动内存回收功能,所以Redis在自己的对象系统中构建了一个引用计数(reference counting)技术实现的内存回收机制,通过这一机制,程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对象并进行内存回收。

       每个对象的引用计数信息有RedisObject结构的refcount属性记录

       对象的引用计数信息会随着对象的使用状态而不断改变:

  1. 在创建一个新对象时,引用计数的值会被初始化为1;
  2. 当对象被一个新程序使用时,引用计数值增1;
  3. 当对象不再被一个程序使用时,引用计数值减1;
  4. 当对象的引用计数值变为0时,对象所占用的内存就会被释放;

对象共享

       对象的引用计数属性除了实现引用计数内存回收机制之外,还带有对象共享的作用。

       Redis会共享值为0-9999的字符串对象;

       共享对象不仅只有字符串键可以使用,五种Redis对象都可以使用这些共享对象

       受到CPU时间的限制,Redis只对包含整数值的字符串进行共享。只有在共享对象和目标对象完全相同的情况下,程序才会将共享对象 用作键的值对象,而一个共享对象保存的值越复杂,验证共享对象和目标对象是否相同所需要的复杂度就越高,消耗的CPU时间也越多;

对象的空转时间

       RedisObject结构包含的最后一个属性为lru属性,该属性记录了对象最后一次被命令程序访问的时间;如果服务器打开了maxmemory选项,那么当服务器占用的内存数超过了maxmemory选项所设置的上限值时,空转时间较长的那部分键会优先被服务器释放,从而回收内存;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值