0
点赞
收藏
分享

微信扫一扫

Redis对象的refcount与lru属性(内存回收、对象共享、空转时长)

本笔记参考《Redis设计与实现》 P84~P88

内存回收

Redis在对象系统中使用reference counting技术实现了内存回收机制。程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对象并进行内存回收。

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

refcount会随着对象的使用状态而不断变化:

  • 创建一个新对象时,refcount被初始化为1
  • 当对象被一个新程序使用时,refcount++
  • 当对象不再被一个程序使用时,refcount–
  • 当对象引用计数为0时,对象所占内存被释放

一些API:

函数

作用

incrRefCount

引用计数+1

decrRefCount

引用计数-1 ,为0时释放对象

resetRefCount

引用计数设置为0,不释放对象

举例:

// 创建一个字符串对象s,对象引用计数为1
robj *s = createStringObject(...)
// 对象s执行各种操作
...
// 将对象s的引用计数-1,降为0,导致对象被释放
decrRefCount(s)

对象共享

引用计数还带有对象共享的作用。
在Redis中,让多个键共享同一个值对象需要执行两个步骤:
1、将数据库键的值指向一个现有的值对象
2、将被共享的值对象的引用计数+1
共享对象机制对于节约内存非常有帮助,数据库中保存的相同的值对象对越,对象共享机制就能节约越多的内存。
Redis会在初始化服务器时,创建一万个字符串对象,包含了0~9999的所有整数值。当服务器有用到这些整数字符串对象,就利用的是共享对象,而非新创建对象。
可以使用​​​OBJECT REFCOUNT 对象Key​​​来查看引用计数。
在数据结构中嵌套了字符串对象的独享如(linkedlist编码的列表对象,hashtable编码的哈希对象,hashtable编码的集合对象,zset编码的有序集合对象)
需要注意下面一个问题:
只有共享对象和目标都西昂完全相同时,才会将共享对象的作为键的值对象,所以需要先验证是否相等。
一个共享对象保存的值越复杂,验证是否相等所需要的复杂度就越高:
1、如果是整数型字符串对象,O(1)
2、如果是字符串值的字符串对象,O(n)
3、如果是包含了多个对象的对象,O(n^2)

空转时长

lru属性记录了对象最后一次被命令程序访问的时间

typedef struct redisObject {
// ...
// 引用计数
unsigned lur : 22;
// ...
} robj;

使用​​OBJECT IDLETIME​​​可以打印出键的空转时长(当前时间减去键的值对象的lru时间)。
如果服务器打开了​​​maxmemory​​​选项,并且回收内存的算法为​​volatile-lru​​​或者​​allkeys-lru​​​,那么服务器占用的内存数超过​​maxmemory​​设置的上限时,空转时长较搞的那部分键会被服务器释放。


举报

相关推荐

0 条评论