Redis源码分析(二十八)---object创建和释放redisObject对象
今天的学习效率比较高,把Rio分析完了,又顺便学习了其中的RedisObject的文件,只要讲的就是RedisObject的一些转换和创建。里面的大多数方法都是非常类似的。列出里面长长的API列表: /* ------------ API --------------------- */robj *createObject(int ty
今天的学习效率比较高,把Rio分析完了,又顺便学习了其中的RedisObject的文件,只要讲的就是RedisObject的一些转换和创建。里面的大多数方法都是非常类似的。列出里面长长的API列表:
/* ------------ API --------------------- */ robj *createObject(int type, void *ptr) /* 最初的创建robj对象方法,后面的创建方法与此类似 */ robj *createStringObject(char *ptr, size_t len) robj *createStringObjectFromLongLong(long long value) robj *createStringObjectFromLongDouble(long double value) robj *dupStringObject(robj *o) robj *createListObject(void) robj *createZiplistObject(void) robj *createSetObject(void) robj *createIntsetObject(void) robj *createHashObject(void) robj *createZsetObject(void) robj *createZsetZiplistObject(void) void freeStringObject(robj *o) /* free Obj中的特定对象,这里free的是r->ptr */ void freeListObject(robj *o) void freeSetObject(robj *o) void freeZsetObject(robj *o) void freeHashObject(robj *o) /* 释放hashObject有2种形式,1个是o-ptr的字典对象,还有1个回事压缩表o->ptr */ void incrRefCount(robj *o) /* robj对象增减引用计数,递增robj中的refcount的值 */ void decrRefCount(robj *o) /* 递减robj中的引用计数,引用到0后,释放对象 */ void decrRefCountVoid(void *o) robj *resetRefCount(robj *obj) int checkType(redisClient *c, robj *o, int type) /* 检查robj的类型是否为给定的Type类型 */ int isObjectRepresentableAsLongLong(robj *o, long long *llval) robj *tryObjectEncoding(robj *o) /* 编码一个robj中的额字符对象,主要是为了省空间 */ robj *getDecodedObject(robj *o) /* 获取解码后的robj */ int compareStringObjectsWithFlags(robj *a, robj *b, int flags) int compareStringObjects(robj *a, robj *b) int collateStringObjects(robj *a, robj *b) int equalStringObjects(robj *a, robj *b) size_t stringObjectLen(robj *o) int getDoubleFromObject(robj *o, double *target) /* 从robj中获取double数值 */ int getDoubleFromObjectOrReply(redisClient *c, robj *o, double *target, const char *msg) int getLongDoubleFromObject(robj *o, long double *target) int getLongDoubleFromObjectOrReply(redisClient *c, robj *o, long double *target, const char *msg) int getLongLongFromObject(robj *o, long long *target) int getLongLongFromObjectOrReply(redisClient *c, robj *o, long long *target, const char *msg) int getLongFromObjectOrReply(redisClient *c, robj *o, long *target, const char *msg) char *strEncoding(int encoding) unsigned long estimateObjectIdleTime(robj *o) robj *objectCommandLookup(redisClient *c, robj *key) /* obj的查找命令, */ robj *objectCommandLookupOrReply(redisClient *c, robj *key, robj *reply) void objectCommand(redisClient *c)
/* 最初的创建robj对象方法 */ robj *createObject(int type, void *ptr) { robj *o = zmalloc(sizeof(*o)); o->type = type; o->encoding = REDIS_ENCODING_RAW; o->ptr = ptr; o->refcount = 1; /* Set the LRU to the current lruclock (minutes resolution). */ o->lru = server.lruclock; return o; }
/* free Obj中的特定对象 */ void freeStringObject(robj *o) { if (o->encoding == REDIS_ENCODING_RAW) { sdsfree(o->ptr); } }
switch(o->type) { case REDIS_STRING: freeStringObject(o); break; case REDIS_LIST: freeListObject(o); break; case REDIS_SET: freeSetObject(o); break; case REDIS_ZSET: freeZsetObject(o); break; case REDIS_HASH: freeHashObject(o); break; default: redisPanic("Unknown object type"); break; }
/* robj对象增减引用计数,递增robj中的refcount的值 */ void incrRefCount(robj *o) { //递增robj中的refcount的值 o->refcount++; }
/* 递减robj中的引用计数,引用到0后,释放对象 */ void decrRefCount(robj *o) { //如果之前的引用计数已经<=0了,说明出现异常情况了 if (o->refcount <= 0) redisPanic("decrRefCount against refcount <= 0"); if (o->refcount == 1) { //如果之前的引用计数为1,再递减一次,恰好内有被任何对象引用了,所以就可以释放对象了 switch(o->type) { case REDIS_STRING: freeStringObject(o); break; case REDIS_LIST: freeListObject(o); break; case REDIS_SET: freeSetObject(o); break; case REDIS_ZSET: freeZsetObject(o); break; case REDIS_HASH: freeHashObject(o); break; default: redisPanic("Unknown object type"); break; } zfree(o); } else { //其他对于>1的引用计数的情况,只需要按常规的递减引用计数即可 o->refcount--; } }
/* Try to encode a string object in order to save space */ /* 编码一个robj中的额字符对象,主要是为了省空间 */ robj *tryObjectEncoding(robj *o) { long value; sds s = o->ptr; size_t len; if (o->encoding != REDIS_ENCODING_RAW) //如果robj已经被编码了,则直接返回 return o; /* Already encoded */ /* It's not safe to encode shared objects: shared objects can be shared * everywhere in the "object space" of Redis. Encoded objects can only * appear as "values" (and not, for instance, as keys) */ /* 如果robj的引用计数超过1个人引用的时候,是不安全的去编码obj,因为对象是共享的 */ if (o->refcount > 1) return o; /* Currently we try to encode only strings */ redisAssertWithInfo(NULL,o,o->type == REDIS_STRING); /* Check if we can represent this string as a long integer */ len = sdslen(s); if (len > 21 || !string2l(s,len,&value)) { /* We can't encode the object... * * Do the last try, and at least optimize the SDS string inside * the string object to require little space, in case there * is more than 10% of free space at the end of the SDS string. * * We do that for larger strings, using the arbitrary value * of 32 bytes. This code was backported from the unstable branch * where this is performed when the object is too large to be * encoded as EMBSTR. */ if (len > 32 && o->encoding == REDIS_ENCODING_RAW && sdsavail(s) > len/10) { //调用sdsRemoveFreeSpace把0->ptr中的字符串中的空格给移除掉 o->ptr = sdsRemoveFreeSpace(o->ptr); } /* Return the original object. */ return o; } .....
/* Get a decoded version of an encoded object (returned as a new object). * If the object is already raw-encoded just increment the ref count. */ /* 获取解码后的robj */ robj *getDecodedObject(robj *o) { robj *dec; if (o->encoding == REDIS_ENCODING_RAW) { //如果没有编码方式,则直接增加引用计数,并返回 incrRefCount(o); return o; } if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_INT) { char buf[32]; //如果是string,Type而且是encoding_int方式的,先做一步转换 ll2string(buf,32,(long)o->ptr); dec = createStringObject(buf,strlen(buf)); return dec; } else { redisPanic("Unknown encoding type"); } }

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

通过指定配置文件重启Redis:1. 找到配置文件(通常位于conf子目录中的redis.conf);2. 修改所需配置(如更改端口);3. 使用redis-server /path/to/redis.conf命令通过配置文件重启Redis(其中/path/to/redis.conf为修改后配置文件的路径);4. 使用redis-cli验证是否已成功重启。

Redis内存飙升的原因包括:数据量过大、数据结构选择不当、配置问题(如maxmemory设置过小)、内存泄漏。解决方法有:删除过期数据、使用压缩技术、选择合适的结构、调整配置参数、检查代码是否存在内存泄漏、定期监控内存使用情况。

Redis内存碎片是指分配的内存中存在无法再分配的小块空闲区域。应对策略包括:重启Redis:彻底清空内存,但会中断服务。优化数据结构:使用更适合Redis的结构,减少内存分配和释放次数。调整配置参数:使用策略淘汰最近最少使用的键值对。使用持久化机制:定期备份数据,重启Redis清理碎片。监控内存使用情况:及时发现问题并采取措施。

Redis 重启后数据仍然存在。Redis 将数据存储在内存中,重启不会删除内存数据。Redis 还提供持久化功能,通过 RDB 或 AOF 文件将数据保存到硬盘,确保重启后数据可从持久化文件中恢复。

不同操作系统中重启 Redis 服务的方法:Linux/macOS:使用 systemctl 命令(systemctl restart redis-server)或 service 命令(service redis-server restart)。Windows:使用 services.msc 工具(在运行对话框中输入 "services.msc" 并按 Enter)并右键单击 "Redis" 服务,选择 "Restart"。

Redis持久化会额外占用内存,RDB在生成快照时临时增加内存占用,AOF在追加日志时持续占用内存。影响因素包括数据量、持久化策略和Redis配置。要减轻影响,可合理配置RDB快照策略、优化AOF配置、升级硬件和监控内存使用情况。此外,在性能和数据安全之间寻求平衡至关重要。

Redis 内存大小设置需要考虑以下因素:数据量及增长趋势:估算存储数据的大小和增长率。数据类型:不同类型(如列表、哈希)占用内存不同。缓存策略:全缓存、部分缓存和淘汰策略会影响内存使用。业务峰值:预留足够内存应对流量高峰。

Redis重启命令为redis-server。此命令用于加载配置文件,创建数据结构,启动Redis服务器并侦听客户端连接。用户可以在终端中执行"redis-server [选项]"命令重新启动Redis服务器,常用选项包括后台运行、指定配置文件路径、指定监听端口、仅在数据丢失时重新加载快照等。注意,重新启动服务器会断开所有客户端连接,请务必在重启前保存必要数据。
