Redis之对象

redis并没有直接使用我们之前介绍的那些数据结构来实现键值对数据库,而是基于这些数据结构创建了一个对象系统,这个系统包含字符串对象、列表对象、哈希对象、集合对象、有序集合对象五种类型的对象,每种对象都用到了至少一种我们前面所介绍的数据结构。通过这五种不同类型的对象,redis可以在执行命令之前,根据对象的类型来判断一个对象是否可以执行给定的命令。除此之外,redis的对象系统还实现了基于引用计数计数的内存回收机制,当程序不再使用某个对象的时候,这个对象所占用的内存就会被自动释放;另外,redis还通过引用计数计数实现了对象共享机制,这一机制可以在适当的条件下,通过多个数据库键共享同一个对象来节约内存。最后redis的对象带有访问时间记录信息,该信息可以用于计算数据库键的空转时长。
对象类型及编码

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

每次当我们在redis的数据库中新创建一个键值对时,我们至少会创建两个对象,一个对象用作键值对的键,另一个对象用作键值对的值。
type:类型

ptr:指向对象的底层实现数据结构,而这些数据结构仅有对象的encoding属性决定
encoding:记录了对象所使用的编码
在这里插入图片描述
每种类型的对象都至少使用了两种不同的编码
在这里插入图片描述
字符串对象
字符串对象的编码可以是int、raw、embstr
如果一个字符串对象保存的时整数值,并且这个数值可以用long类型来表示,那么字符串对象会将整数值保存在字符串对象结构的ptr属性里面,并将字符串对象的编码设置为int。
如果字符串对象保存的是一个字符串值,并且这个字符串值的长度大于32字节,那么字符串对象将使用一个简单动态字符串来保存这个字符串值,并将对象的编码设置为raw。
如果字符串对象保存的是一个字符串值,并且这个字符串值的长度小于等于32字节,那么字符串对象将使用embstr编码的方式来保存这个二字符串值。
embstr编码是专门用于保存短字符串的一种优化编码方式,raw编码会调用两次内存分配函数来分别创建redisObject结构和sdshdr结构,而embstr编码则通过调用一次内存分配函数来分配一块连续的空间,空间一次包含redisObject和sdshdr。
列表对象
列表对象的编码可以是ziplist或者linkedlist
ziplist编码的列表对象使用压缩列表作为底层实现,每个压缩列表节点保存了一个列表元素
在这里插入图片描述

linkedlist编码的列表对象使用双端链表作为底层实现,每个双端链表节点都保存了一个字符串对象,而每个字符串对象都保存了一个列表元素
在这里插入图片描述

当列表对象可以同时满足以下两个条件时,列表对象使用ziplist编码:
1、列表对象保存的所有字符串元素的长度都小于64字节
2、列表对象保存的元素数量小于512个;不能满足这两个条件的列表对象需要使用linkedlist编码
哈希对象
哈希对象的编码可以是ziplist或者hashtable
ziplist编码的哈希对象使用压缩列表作为底层实现,每当有新的键值对要加入到哈希对象时,程序会先将保存了键的压缩列表节点推入到压缩列表表尾,然后再将保存了值的压缩列表节点推入到压缩列表的表尾
在这里插入图片描述
在这里插入图片描述
hashtable编码的哈希对象使用字典作为底层实现:
在这里插入图片描述

当哈希对象可以同时满足以下两个条件时,哈希对象使用ziplist编码:
1、哈希对象保存的所有键值对的键和值的字符串长度都小于64字节
2、哈希对象保存的键值对数量小于512个
集合对象
集合对象的编码可以是inset或者hashtable
在这里插入图片描述
当集合对象可以同时满足以下两个条件时,对象使用inset编码:
1、集合对象保存的所有元素都是整数值
2、集合对象保存的元素数量不超过512个
有序集合对象
有序集合对象的编码可以是ziplist或者skiplist
skiplist编码的有序集合对象使用zset结构作为底层实现,一个紫色调结构同时包含一个字典和一个跳跃表
在这里插入图片描述
当有序集合对象可以同时满足以下两个条件时,对象使用ziplist编码:
1、有序集合保存的元素数量小于128个
2、有序集合保存的所有元素成员的长度都小于64字节
类型检查与命令多态
redis中用于操作键的命令基本可以分为两种类型
1、可以对任何类型键执行
2、只能对特定类型的键执行
类型检查的实现
类型特定命令锁进行的类型检查是通过redisObject结构的type属性来实现的:
1、在执行一个类型特定命令前,服务器会先检查输入数据库键的值对象是否为执行命令所需类型,如果是的话, 服务器就对键执行指定的命令
2、否则,服务器将拒绝执行命令,并向客户端返回一个类型错误
在这里插入图片描述
多态命令的实现
redis除了会根据值对象的类型来判断键是否能够执行指定命令之外,还会根据值对象的编码方式,选择正确的命令实现代码来执行命令
在这里插入图片描述
内存回收
redis在自己的对象系统中构建了一个引用计数技术实现的内存回收机制,通过这一机制,程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对象并进行内存回收。
对象的引用计数信息会随着对象的使用状态而不断变化:
1、在创建一个新对象时,引用计数的值湖北初始化为1
2、当一个新程序使用时,它的引用计数值会被赠一
3、当对象不再被一个程序使用时,它的引用计数值会被减一
4、当对象的引用计数值变为0时,对象所占用的内存会被释放
对象共享
除了用于实现引用计数内存回收机制之外,对象的引用计数属性还带有对象的共享作用。目前来说,redis会在初始化服务器时,创建一万个字符串对象,这些对象包含了从0到9999的所有整数值,当服务器需要用到值为0到9999的字符串对象时,服务器就会使用这些共享对象。
对象的空转时长:lru记录了对象最后一次被命令程序访问的时间。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值