- Redis使用对象来表示数据库中的键和值
- 每种对象都用到了至少一种数据结构:动态字符串、链表、字典、跳跃表、整数集合、压缩列表
- 针对不同的使用场景,为对象设置多种不同的数据结构实现,优化对象在不同场景下的使用效率
- 基于引用计数技术的
内存回收机制
和对象共享机制
- 对象带有访问时间记录信息,
// 对象类型
// 字符串对象
#define OBJ_STRING 0
// 列表对象
#define OBJ_LIST 1
// 集合对象
#define OBJ_SET 2
// 有序集合对象
#define OBJ_ZSET 3
// 哈希对象
#define OBJ_HASH 4
// 对象编码类型
// 简单动态字符串
#define OBJ_ENCODING_RAW 0
// long类型的整数
#define OBJ_ENCODING_INT 1
// 字典
#define OBJ_ENCODING_HT 2
#define OBJ_ENCODING_ZIPMAP 3
// 双端链表
#define OBJ_ENCODING_LINKEDLIST 4
// 压缩列表
#define OBJ_ENCODING_ZIPLIST 5
// 整数
#define OBJ_ENCODING_INTSET 6
// 跳跃表
#define OBJ_ENCODING_SKIPLIST 7
// embstr编码的简单动态字符串
#define OBJ_ENCODING_EMBSTR 8
// 压缩链表
#define OBJ_ENCODING_QUICKLIST 9
// 流
#define OBJ_ENCODING_STREAM 10
/**
* 对象redisObject数据结构
* Redis 存储的 value 数据都是用 redisObject 来封装的
* 包括 string,hash,list,set,zset 在内的所有数据类型
*/
typedef struct redisObject {
/**
* 对象类型:表示当前对象使用的数据类型,
* Redis主要支持5种数据类型:string,hash,list,set,zset。
* 可以使用type {key}命令查看对象所属类型,
* type命令返回的是值对象类型,键都是string类型。
*/
unsigned type:4;
//
/**
* 编码类型:ptr指针所指向对象的底层实现数据结构类型,即当前对象使用了什么数据结构作为对象的底层实现
* 表示Redis内部编码类型,encoding在Redis内部使用,
* 代表当前对象内部采用哪种数据结构实现。
* 理解Redis内部编码方式对于优化内存非常重要 ,
* 同一个对象采用不同的编码实现内存占用存在明显差异,
*/
unsigned encoding:4;
// 缓存策略数据
// 空转时长(idletime) = 当前时间 - lru属性时间
// LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰
// 该算法赋予每个页面一个访问时间字段,用来记录一个页面自上次被访问以来所经历的时间 idletime,当须淘汰一个页面时,选择现有页面中其 idletime 值最大的
/**
* 记录对象最后一次被访问的时间,
* 当配置了maxmemory 和 maxmemory-policy=volatile-lru | allkeys-lru 时,辅助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). */
// LFU是Least Frequently Used的缩写,即最近最不经常使用,是一种常用的页面置换算法,选择引用计数最小的页面予以淘汰
// 该算法赋予每个页面一个引用计数字段,用来记录一个页面使用次数 refcount,当须淘汰一个页面时,选择现有页面中其 refcount 值最小的
/**
* 引用计数:记录当前对象被引用的次数,用于通过引用次数回收内存,
* 当refcount=0时,可以安全回收当前对象空间。
* 使用 object refcount {key} 获取当前对象引用。
*/
int refcount;
/**
* 指底层实现数据结构的指针:保存实际的数据
* 与对象的数据内容相关,如果是整数直接存储数据,否则表示指向数据的指针。
* Redis在3.0 之后对值对象是字符串且长度 <=39 字节的数据,
* 内部编码为 embstr 类型,字符串 sds 和 redisObject 一起分配,从而只要一次内存操作。
* 因此在高并发的场景尽量是我们的字符串保持 39 字节内,
* 减少创建redisObject内存分配次数从而提高性能。
*/
void *ptr;
} robj;
TYPE 命令
查看数据库键【对应的值对象】的类型
OBJECT ENCODING 命令查看数据库键的【值对象】的编码
OBJECT REFCOUNT 命令查看数据库键的【值对象】的引用计数
OBJECT IDLETIME 命令查看数据库键的空转时长,不会修改值对象的lru属性
源码阅读- 文件:src/server.h