Redis对象

Redis的对象系统基于数据结构创建了字符串、列表、哈希、集合和有序集合等对象。对象的类型和编码决定了它们的底层实现,如字符串对象可使用int、raw、embstr编码。内存回收通过引用计数机制实现,当对象引用计数为0时释放内存。此外,Redis还支持对象共享以节省内存,并通过lru属性处理空转时长,用于内存溢出时的选择性删除。
摘要由CSDN通过智能技术生成

Redis对象

Redis并没有直接使用之前那些数据结构实现键值对数据库,而是基于这些数据结构创建了一个对象系统,整个系统包含字符串对象,列表对象那个,哈希对象,集合对象和有序集合对象。

利用对象,Redis可以在执行命令之前,根据对象的类型来判断一个对象是否可以执行给定的命令。

Redis的对象系统还实现了基于引用计数技术的内存回收机制,当程序不再使用某个对象的时候,整一机制可以在适当的条件下,通过让多个数据库键共享一个对象来节约内存。

Redis对象的类型与编码

每当创建一个键值对时,至少会创建两个对象,一个对象用作键值对的键,另一个对象用作键值对的值(健对象和值对象)

redis每个对象都由一个redisObject结构表示

typedef struct redisObject{
//类型
unsigned type:4;
//编码
unsigned encoding: 4;
//指向底层实现数据结构的指针
void *ptr;
}robj;

type属性记录了对象的类型

REDIS_STRING 字符串对象

REDIS_LIST 列表对象

REDIS_HASH 哈希对象

REDIS_SET 集合对象

REDIS_ZSET 有序集合对象

对于键值对来说,键总是一个字符串对象,而值可以是字符串对象,列表对象,哈希对象,集合对象或者是有序集合对象中的一种

encoding属性记录了对象所使用的编码,也就是说这个对象使用了什么数据结构作为对象的底层实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1D1wThrN-1672895245307)(Redis%E5%AF%B9%E8%B1%A1%2009a527d9ba684849933b0be7180d1590/Untitled.png)]

每种类型的对象都至少使用了两种不同的编码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8JTMdO39-1672895245308)(Redis%E5%AF%B9%E8%B1%A1%2009a527d9ba684849933b0be7180d1590/Untitled%201.png)]

因为一种数据结构的底层实现不是固定的,所以通过encoding属性来设定对象所使用的编码,可以极大的提升Redis的灵活性和效率。

字符串对象

字符串对象的编码可以是int,raw,embstr

如果字符串对象保存的是一个字符串值,并且这个字符串值的长度大于32字节,那么字符串对象将使用一个SDS来保存这个字符串值,并将对象的编码设置为raw

如果保存的是一个整数值,并且这个整数可以用long类型表示,那么字符串对象将会将整数值保存在字符串对象结构的ptr属性里面,并将字符串对象的编码设置为int(可以用long double类型表示的浮点数在Redis中也是作为字符串值来保存的)

如果保存的是一个字符串值,并且这个字符串值的长度小于等于32字节,那么字符串对象将会使用embstr编码格式(这是一种专门用于保存短字符串的一种优化编码方式)

编码的转换

int编码的字符串对象和embstr编码的字符串对象在条件满足的情况下,会被转换为raw编码的字符串对象

列表对象

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

linkedlist编码的列表对象在底层的双端链表结构中包含了多个字符串对象

编码转换

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

列表对象保存的所有字符串元素都小于64字节

列表对象保存的元素数量少于512个

(这两个条件的上限值都是可以修改的)

哈希对象

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

对于ziplist,每当有新的键值对要加入到哈希对象时,程序会先将保存了键的压缩列表节点推入到压缩列表尾,然后将保存了值的压缩列表节点推入到压缩列表表尾

这样,保存了同一键值对的两个节点总是紧挨在一起的

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

编码转换

满足两个条件,将会使用ziplist编码:
保存的键值对的键和值的字符串长度都小于64字节

保存的键值对的数量小于512个

(条件都同样可以修改)

集合对象

集合对象的编码可以是inset或者hashtable

inset编码的集合对象使用整数集合作为底层实现

hashtable编码的集合对象使用字典作为底层实现

编码的转换

满足以下两个条件,对象使用intset编码:

保存的元素都是整数值

保存的元素瞬目不超过521个

有序集合对象

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

对于ziplist,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存成员,第二个节点保存分值(score)

skiplist编码使用zset结构作为底层实现,一个zset结构同时包含一个字典和一个跳跃表

typedef struct zset{
zskiplist *zsl;
dict *dict;
}zset;

编码的转换:

使用ziplist编码的两个条件:

保存的元素数目少于128个

长度都小于64

类型检查与命令多态

类型检查

为了保证只有指定类型的键可以执行某些特定的命令,再执行一个类型特定的命令之前,Redis会先检查输入见的类型是否正确。

检查是通过redisBbject结构的type属性来实现的。

多态命令的实现

Redis除了会根绝值对象的类型来判断键是否能够执行指定命令外,还会根据值对象的编码方式,选择正确的命令实现代码来自行命令。

内存回收

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

每个对象的引用计数信息由redisObject结构的ref-count属性记录

typedef struct redisObject{
	//引用计数
int refcount;
}robj

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

当对象的引用计数值变为0时,对象所占用的内存就会被释放

对象共享

在Redis中,让多个键共享同一个值对象需要执行以下两个步骤:

1.将数据库键的值指针指向一个现有的值对象

2.将被共享的值对象的引用计数+1

目前来说:Redis会在初始化服务器时,创建一万个字符串对象,这些对象包含了从0-9999的所有整数值,当服务器需要用到0-9999的字符串对象时,服务器就会使用这些共享对象

对象的空转时长

redisObject包含的最后一个属性为lru属性,该属性记录了对象最后一次被命令程序访问的时间

空转时长就是通过将当前时间减去键的值对像的lru时间计算得出的

另一个作用是,如果服务器打开了maxmemory选项,并且服务器用于回收内存的算法为volatile-lru或者allkeys-lru,那么服务器占用的内存书超过了maxmemory选项所设置的上限值时,空转市场较高的那部分键会优先被服务器释放

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值