Redis~对象(string、list、hash、set、zset等) 的对象检查、空转时长、内存回收与对象共享

对象检查

  • Redis中用于操作键的命令基本上可以分为两种类型:
    ①其中一种命令可以对任何类型的键执行,比如说DEL命令、EXPIRE命令、RENAME命 令、TYPE命令、OBJECT命令等
    ②而另一种命令只能对特定类型的键执行,比如说:

  • SET、GET、APPEND、STRLEN等命令只能对字符串键执行;

  • HDEL、HSET、HGET、HLEN等命令只能对哈希键执行

  • RPUSH、LPOP、LINSERT、LLEN等命令只能对列表键执行;

  • SADD、SPOP、SINTER、SCARD等命令只能对集合键执行

  • ZADD、ZCARD、ZRANK、ZSCORE等命令只能对有序集合键执行

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

  • 类型特定命令所进行的类型检查是通过redisObject结构的type属性来实现的

typedef struct redisObject {
    //类型
    unsigned type:4;
    //编码
    unsigned encoding:4;
    //指向底层实现数据结构的指针
    void *ptr;
    // ...
} robj;
  • 在执行一个类型特定命令之前,服务器会先检查输入数据库键的值对象是否为执行命令所需的类型,如果是的话,服务器就对键执行指定的命令
  • 否则,服务器将拒绝执行命令,并向客户端返回一个类型错误

多态命令的实现

  • Redis除了会根据值对象的类型来判断键是否能够执行指定命令之外,还会根据值对象的编码方式,选择正确的命令实现代码来执行命令
  • 我们说过,列表对象有ziplist和linkedli6st两种编码可用,其中前者使用压缩列表API来实现列表命令,而后者则使用双端链表API来实现列表命令
    在这里插入图片描述

空转时长

  • redisObject结构包含的最后一个属性为lru属性,该属性记录了对象最后一次被命令程序访问的时间
typedef struct redisObject {
    // ...
    unsigned lru:22;
    // ...
} robj;
  • OBJECT IDLETIME命令可以打印出给定键的空转时长
    在这里插入图片描述
  • 这一空转时长就是通过将当前时间减去键的值对象的lru时间计算得出的
  • 键的空转时长还有另外一项作用:如果服务器打开了maxmemory选项,并且服务器用于回收内存的算法为volatile-lru或者allkeys-lru,那么当服务器占用的内存数超过了maxmemory选项所设置的上限值时,空转时长较高的那部分键会优先被服务器释放,从而回收内存

内存回收

  • 因为C语言并不具备自动内存回收功能,所以Redis在自己的对象系统中构建了一个引用计数(reference counting)技术实现的内存回收机制,通过这一机制,程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对象并进行内存回收
  • 我们知道在java中使用可达性分析进行判决垃圾, 不使用引用计数, 是因为在java中对象之间存在互相引用, 但是在Redis中这是不存在的对象之间互相引用的, 并且如果是字符串对象其使用的也是对象共享机制,不会出现互相引用

refcount属性

  • 每个对象的引用计数信息由redisObject结构的refcount属性记录:
typedef struct redisObject {
    // ...
    //引用计数
    int refcount;
    // ...
} robj;
  • 对象的引用计数信息会随着对象的使用状态而不断变化:
  1. 在创建一个新对象时,引用计数的值会被初始化为1
  2. 当对象被一个新程序使用时,它的引用计数值会被增一
  3. 当对象不再被一个程序使用时,它的引用计数值会被减一
  4. 当对象的引用计数值变为0时,对象所占用的内存会被释放
  • 对象的整个生命周期可以划分为创建对象、操作对象、释放对象三个阶段。

对象共享

  • 除了用于实现引用计数内存回收机制之外,对象的引用计数属性(refcount属性)还带有对象共享的作用
  • 在Redis中,让多个键共享同一个值对象需要执行以下两个步骤:
  1. 将数据库键的值指针指向一个现有的值对象
  2. 将被共享的值对象的引用计数增一
  • 目前来说,Redis会在初始化服务器时,创建一万个字符串对象,这些对象包含了从0到9999的所有整数值,当服务器需要用到值为0到9999的字符串对象时,服务器就会使用这些共享对象,而不是新创建对象

  • Redis只对字符串对象进行共享,并且只对包含整数值的字符串对象进行共享

  • 其原因就是我们在使用对象共享的时候需要进行检验, 只有共享对象和目标对象都完全相同的情况下才能使用对象共享, 那如果不是整数值的字符串对象, 检验起来是很费CPU时间的, 对于Redis这种超快速数据库来说还不如直接新建立一个对象, 所以Redis只对包含整数值的字符串进行共享

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值