Redis6.0.8源码解析三之(对象)


在redis中,对象就是封装了数据结构的实现.

对象的数据结构

typedef struct redisObject {
    //类型
    unsigned type:4;
    //编码
    unsigned encoding:4;
    //记录对象最后一次访问时间,用于垃圾回收
    //可通过OBJECT IDLETIME 查看给定键的空转时长(这个命令不会修改LRU时间),也就是多久没访问.
    //根据lru属性,若服务器回收内存算法为volatile-lru或者all-lru,且服务器内存占用超过maxmemory,则lru时间长的就会被回收.
    unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
                            * LFU data (least significant 8 bits frequency
    //引用计数                        * and most significant 16 bits access time). */
    int refcount;
    //指向底层数据结构的指针
    void *ptr;
} robj;

类型

当存一对key和value时,分别创建2个对象,键对象始终为字符串类型,而value可以是如下类型之一.
在这里插入图片描述
可使用Type命令查看类型

编码

ptr具体指向那个数据结构,取决于encoding
每种数据结构对应编码如下图所示:
在这里插入图片描述
每种类型的对象可以使用的编码,如下图所示:
在这里插入图片描述
可使用OBJECT ENCODING查看编码类型
在这里插入图片描述

空转时长

可通过OBJECT IDLETIME 查看给定键的空转时长(这个命令不会修改LRU时间),也就是多久没访问.
根据lru属性,若服务器回收内存算法为volatile-lru或者all-lru,且服务器内存占用超过maxmemory,则lru时间长的就会被回收.

内存回收与内存共享

生命周期如下:

  • 创建时,引用计数初始化1
  • 被新程序引用,则引用计数+1
  • 不在引用,则-1
  • 为0,则释放内存

在这里插入图片描述
当对象共享时,引用计数也会+1。目前redis只共享包含整数值的字符串对象.因为共享数字,只需要拿出value对比就行了,复杂度为O(1)。而字符串的话需要遍历每个字符串,复杂度为O(N).如果包含多个值,那么就需要嵌套循环遍历.复杂度为O(N^2).

注意:redis会共享0~9999的字符串对象
当创建一个对象,会有2个引用.
可通过OBJECT REFCOUNT查看引用次数.

在这里插入图片描述

字符串对象

字符串对象的编码可以是int,embstr,raw.
注意:long double浮点数也是字符串存储的.
在这里插入图片描述

int

使用该编码的前提条件:

  • 保存的是整数值
  • 可被long类型表示.

保存步骤:将整数保存ptr(将void*变成long),并将属性编码设置int

raw

前提条件:

  • 保存的是字符串
  • 长度>32字节
    使用SDS保存
    在这里插入图片描述

embstr

前提条件:

  • 保存的是字符串
  • 长度<=32字节

步骤:和raw一样,不过区别在于raw需要分别为redisObject和sds结构分配内存,而embstr则只需要分配一次就行.分配的空间redisObject和sds相邻.
在这里插入图片描述
优点:

  • 与raw相比较,分配资源少了一次
  • 释放内存也少了一次
  • 因为2对象相邻,读起来不需要寻址咯.

编码何时转换?

存的是int类型,当执行appen类似命令时,会先转换成字符串,然后执行append操作.
embstr执行append类似也同上.所以embstr只支持只读.

命令以及实现

在这里插入图片描述

列表对象

ziplist

前提条件:

  • 列表对象保存的所有字符串元素的长度<64字节.可通过list-max-zpilist-value配置
  • 元素数量<512.可通过list-max-zpilist-entries配置

当插入三个数据
在这里插入图片描述

结构如下:
在这里插入图片描述

linkedList

在这里插入图片描述

命令以及实现

在这里插入图片描述

hash对象

ziplist

前提条件:

  • 保存的所有键和值的字符串长度<64.可通过hash-max-zpilist-value配置
  • 键值对数量<512,可通过hash-max-zpilist-entries配置

步骤:键存压缩列表尾部,紧接着值存队列尾部
存储了三个键值对的结构样子:
在这里插入图片描述

hashtable

在这里插入图片描述

命令以及实现

在这里插入图片描述

集合对象

intset

前提条件:

  • 保存的值为整数
  • 值数量<512,可通过set-max-intset-entries配置

在这里插入图片描述

hashtable

键为存的集合值,值为null.
和hashSet一样,键为集合值,value为Object而已.
在这里插入图片描述

命令以及实现

在这里插入图片描述

有序集合

ziplist

前提条件:

  • 保存的每个成员长度 < 64byte,可通过zset-max-zpilist-value配置
  • 数量<128,可通过zset-max-zpilist-entries 配置
    在这里插入图片描述

skiplist

分别采用跳跃表+字典方式保存.

//实现有序集合
//在这里,字典表和跳跃表每个成员和score,都共享.所以不会浪费内存
typedef struct zset {
    //存储key-score,这样根据key查找,复杂度为O(1)
    dict *dict;
    //根据score,有序存储.执行范围查找时,就无须排序.
    zskiplist *zsl;
} zset;

在这里插入图片描述

命令以及实现

在这里插入图片描述

多台命令实现

redis有2种命令,一种是五种数据类型都可使用的命令,如DEL,另外一种是五种数据类型特定的命令.
在执行命令时,redis会看看是否与类型匹配,不匹配直接异常,
如果匹配则,再次查看数据结构实现,根据不同的数据结构实现选择不同的实现方法.
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值