在前面的文章中,我介绍了Redis的底层数据结构,但Redis对外提供的命令并没有直接使用它们,而是基于它们构建更高级的数据对象,总共包括5中对象类型,分别为【字符串对象】、【列表对象】、【哈希对象】、【集合对象】和【有序集合对象】,Redis实现对象系统的思想是:每一种对象都使用多种底层数据结构进行实现,具体使用哪种数据结构基于使用场景进行选择,并且可以在触发条件时进行转换。
一.Redis对象结构体
1.type字段
表示该对象的类型,具体枚举值如下图所示:
Redis对象类型枚举
Redis提供了【type】命令来获取某个对象具体的类型,例如:
127.0.0.1:6379> set a 1
OK
127.0.0.1:6379> type a
string
2.encoding字段
表示该对象是哪种编码,也就是底层使用哪种数据结构进行实现,具体枚举值如下图所示:
Redis对象编码枚举
Redis提供了【object encoding】命令来获取某个对象的编码,例如:
127.0.0.1:6379> object encoding a
"int"
3.lru字段
保存了该对象最后一次被访问的时间戳,主要用于计算这个对象的idle时长,以便根据idle时长选择是否对其内存进行回收。
Redis提供了【object idletime】命令来获取某个对象的idle时长,例如:
127.0.0.1:6379> object idletime a
(integer) 252
4.refcount字段
表示该对象被引用次数,当某个对象不再被引用时(即refcount=0),它占用的内存将被释放;此外,Redis还会在服务器初始化时创建一系列共享对象,例如值在[0,10000]区间内的整数,会被创建为类型为字符串、编码为整数的共享对象,其refcount字段永远为1,因而常驻在内存中,来避免创建相同对象,浪费内存。
Redis提供了【object refcount】命令来获取某个对象的引用次数,例如:
127.0.0.1:6379> object refcount a
(integer) 4
Redis共享对象(常用整数)
Redis在三种情况下会修改refcount的值
第一种:对象初始化时设置为1
第二种:对象被某个程序引用时,refcount加1
第三种:对象被某个程序弃用时,refcount减1,且如果减到0则释放其占用的内存
5.ptr字段
指向底层数据结构的指针,保存了数据的真实值。
二.Redis对象的操作
1.创建对象
其中,对于lru时钟的获取,Redis在3.0版本做了优化。
首先,Redis会有一个专门的线程作为定时事件,不停的刷新系统当前时间,而server.hz就是serverCron运行的频率。所以,在获取lru时钟的时候,会优先根据hz和时钟精度判断是否可以获取系统缓存的时钟值,如果不可以再进行系统调用获取时钟。
此外,Redis还封装了一系列的创建具体类型对象的方法。但实际上,除了嵌入式SDS之外,其他都是调用createObject方法。方法如下:
创建字符串对象
createStringObject(const char *ptr, size_t len)
创建SDS编码的字符串对象
createRawStringObject(const char *ptr, size_t len)
创建嵌入式SDS编码的字符串对象
createEmbeddedStringObject(const char *ptr, size_t len)
根据传入的longlong整型值,创建一个字符串对象
createStringObjectFromLongLong(long long value)
根据传入的long double类型值,创建一个字符串对象
createStringObjectFromLongDouble(long double value, inthumanfriendly)
创建压缩列表编码的列表对象
createZiplistObject(void);
创建集合对象
*createSetObject(void)
创建整型集合编码的集合对象
createIntsetObject(void)
创建哈希对象
createHashObject(void)
创建有序集合对象
createZsetObject(void)
创建压缩列表编码的有序集合对象
createZsetZiplistObject(void)
在后面分析每种对象的文章中我会逐一介绍。
2.释放对象
正如前文所说,Redis根据对象的refcount字段判断是否需要释放当前对象。
当某个程序弃用该对象时,Redis会对该对象的refcount值进行判断:
如果该值为非正数,则是一次异常调用
如果该值为1,则根据对象类型选择对应方法释放内存
如果该值大于1,则refcount--
而每种类型的释放方法中,又会根据编码去掉用底层数据结构的释放内存方法,以列表对象为例,如果该对象是双端列表实现,则调用双端列表的释放内存方法,否则释放压缩列表的释放内存方法:
3.计算对象空转时长
Redis基于近似LRU算法,计算某个对象的空转时长。在当前时钟大于等于对象的lru时钟时,说明该对象已经空转一段时间,返回他们的差值即可;而当前时钟小于lru时钟时,则需要将它们的差值(负数)与LRU时钟最大值进行相加再返回。Redis会在需要使用LRU策略清理内存时,从所有key中进行采样,从中淘汰空转时长最长的key。
4.对象交互命令
前文中提到,Redis针对对象实现了3个命令,分别为获取引用次数命令【object refcount】、获取编码命令【object encoding】和获取空转时长命令【object idletime】。
三.Redis对象思维导图
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。