您好,登录后才能下订单哦!
Redis是一个高性能的键值存储系统,广泛应用于缓存、消息队列、排行榜等场景。在Redis中,所有的键和值都是以对象的形式存在的,这些对象通过redisObject
结构体来表示。本文将详细介绍redisObject
结构体的定义、作用以及其在Redis中的使用方式。
在Redis中,所有的数据都是以键值对的形式存储的。键和值都是对象,这些对象通过redisObject
结构体来表示。redisObject
结构体是Redis中最基本的数据结构之一,它包含了对象的类型、编码方式、引用计数等信息。
Redis支持多种数据类型,包括字符串(String)、列表(List)、哈希(Hash)、集合(Set)、有序集合(Sorted Set)等。每种数据类型都有对应的对象类型,这些类型在redisObject
结构体中以枚举的形式定义。
Redis为了优化内存使用和性能,为每种数据类型提供了多种编码方式。例如,字符串类型可以有RAW
、EMBSTR
、INT
等编码方式,列表类型可以有ZIPLIST
、LINKEDLIST
等编码方式。编码方式的选择取决于数据的大小和结构。
Redis使用引用计数来管理对象的内存。当一个对象被多个地方引用时,引用计数会增加;当引用减少时,引用计数会减少。当引用计数为0时,对象会被释放。
redisObject
结构体定义redisObject
结构体定义在Redis源码的server.h
文件中。以下是redisObject
结构体的定义:
typedef struct redisObject {
unsigned type:4; // 对象类型
unsigned encoding:4; // 编码方式
unsigned lru:LRU_BITS; // LRU时间或LFU数据
int refcount; // 引用计数
void *ptr; // 指向实际数据的指针
} robj;
type: 表示对象的类型,占用4个比特位。Redis中定义了以下几种对象类型:
OBJ_STRING
: 字符串类型OBJ_LIST
: 列表类型OBJ_SET
: 集合类型OBJ_ZSET
: 有序集合类型OBJ_HASH
: 哈希类型OBJ_MODULE
: 模块类型OBJ_STREAM
: 流类型encoding: 表示对象的编码方式,占用4个比特位。Redis中定义了多种编码方式,例如:
OBJ_ENCODING_RAW
: 原始编码,用于字符串类型OBJ_ENCODING_INT
: 整数编码,用于字符串类型OBJ_ENCODING_EMBSTR
: 嵌入式字符串编码,用于字符串类型OBJ_ENCODING_HT
: 哈希表编码,用于哈希类型OBJ_ENCODING_ZIPLIST
: 压缩列表编码,用于列表、哈希、有序集合类型OBJ_ENCODING_LINKEDLIST
: 链表编码,用于列表类型OBJ_ENCODING_SKIPLIST
: 跳跃表编码,用于有序集合类型OBJ_ENCODING_QUICKLIST
: 快速列表编码,用于列表类型OBJ_ENCODING_INTSET
: 整数集合编码,用于集合类型OBJ_ENCODING_STREAM
: 流编码,用于流类型lru: 表示对象的LRU(Least Recently Used)时间或LFU(Least Frequently Used)数据,占用24个比特位。这个字段用于实现Redis的淘汰策略。
refcount: 表示对象的引用计数。当一个对象被多个地方引用时,引用计数会增加;当引用减少时,引用计数会减少。当引用计数为0时,对象会被释放。
ptr: 指向实际数据的指针。根据对象的类型和编码方式,ptr
指向的数据结构会有所不同。例如,对于字符串类型,ptr
可能指向一个SDS
(Simple Dynamic String)结构;对于列表类型,ptr
可能指向一个quicklist
结构。
不同的对象类型可以有不同的编码方式。例如,字符串类型可以有RAW
、EMBSTR
、INT
等编码方式,而列表类型可以有ZIPLIST
、LINKEDLIST
、QUICKLIST
等编码方式。Redis会根据数据的大小和结构自动选择合适的编码方式,以优化内存使用和性能。
redisObject
的使用在Redis中,所有的键和值都是以redisObject
的形式存在的。当我们执行一个命令时,Redis会根据命令的类型和参数创建或操作相应的redisObject
。
当我们向Redis中插入一个键值对时,Redis会创建一个redisObject
对象来表示这个键和值。例如,当我们执行SET key value
命令时,Redis会创建一个字符串类型的redisObject
对象来表示value
,并将其与key
关联。
robj *createStringObject(const char *ptr, size_t len) {
if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT) {
return createEmbeddedStringObject(ptr, len);
} else {
return createRawStringObject(ptr, len);
}
}
在上面的代码中,createStringObject
函数会根据字符串的长度选择不同的编码方式。如果字符串长度小于等于OBJ_ENCODING_EMBSTR_SIZE_LIMIT
,则使用EMBSTR
编码;否则,使用RAW
编码。
当我们执行一个命令时,Redis会根据命令的类型和参数操作相应的redisObject
。例如,当我们执行LPUSH list value
命令时,Redis会操作一个列表类型的redisObject
对象,并将value
插入到列表的头部。
void lpushCommand(client *c) {
robj *subject;
if ((subject = lookupKeyWriteOrReply(c, c->argv[1], shared.null[c->resp])) == NULL) return;
if (subject->type != OBJ_LIST) {
addReply(c, shared.wrongtypeerr);
return;
}
for (int j = 2; j < c->argc; j++) {
listTypePush(subject, c->argv[j], LIST_HEAD);
}
addReplyLongLong(c, listTypeLength(subject));
signalModifiedKey(c, c->db, c->argv[1]);
notifyKeyspaceEvent(NOTIFY_LIST, "lpush", c->argv[1], c->db->id);
server.dirty += (c->argc - 2);
}
在上面的代码中,lpushCommand
函数首先查找键对应的redisObject
对象,然后检查对象的类型是否为列表类型。如果是列表类型,则将value
插入到列表的头部。
当一个对象不再被引用时,Redis会释放该对象。释放对象的过程包括减少引用计数、释放实际数据的内存等。
void decrRefCount(robj *o) {
if (o->refcount == 1) {
switch(o->type) {
case OBJ_STRING: freeStringObject(o); break;
case OBJ_LIST: freeListObject(o); break;
case OBJ_SET: freeSetObject(o); break;
case OBJ_ZSET: freeZsetObject(o); break;
case OBJ_HASH: freeHashObject(o); break;
case OBJ_MODULE: freeModuleObject(o); break;
case OBJ_STREAM: freeStreamObject(o); break;
default: serverPanic("Unknown object type"); break;
}
zfree(o);
} else {
if (o->refcount <= 0) serverPanic("decrRefCount against refcount <= 0");
if (o->refcount != OBJ_SHARED_REFCOUNT) o->refcount--;
}
}
在上面的代码中,decrRefCount
函数会根据对象的类型调用相应的释放函数,并最终释放redisObject
对象本身。
redisObject
结构体是Redis中最基本的数据结构之一,它包含了对象的类型、编码方式、引用计数等信息。通过redisObject
,Redis能够高效地管理各种数据类型,并根据数据的大小和结构自动选择合适的编码方式,以优化内存使用和性能。
在实际使用中,Redis会根据命令的类型和参数创建或操作相应的redisObject
对象。当一个对象不再被引用时,Redis会释放该对象,以避免内存泄漏。
通过深入了解redisObject
结构体的定义和使用方式,我们可以更好地理解Redis的内部工作原理,从而在实际应用中更好地利用Redis的性能优势。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。