Redis对象——内存回收,对象共享和空转时长

news2024/12/29 8:54:40

一. 内存回收 

        因为C语言不具备内存回收功能,所以Redis在自己的对象系统中构建了一个引用计数技术实现内存回收机制。通过这一机制,程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对象并进行内存回收。

        内每一个对象的引用计数信息由redisObject结构的refcount属性记录:

typedef struct redisObject {
    unsigned type:4;
    unsigned encoding:4;
    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). */
    int refcount;
    void *ptr;
} robj;

        对象的引用计数信息会随着对象的使用状态而不断变化:

  • 在创建一个新对象时,引用计数的值会被初始化为1。
  • 当对象被一个新程序使用时,他的引用计数会被增1。
  • 当对象不被程序使用时,他的引用计数会被减1。
  • 当对象的引用计数值变为0时,对象所占有的内存会被释放掉。

        下面是对引用计数进行操作的接口:

//创建对象
robj *createObject(int type, void *ptr);
robj *createStringObject(const char *ptr, size_t len);
robj *createRawStringObject(const char *ptr, size_t len);
robj *createEmbeddedStringObject(const char *ptr, size_t len);
robj *createStringObjectFromLongLong(long long value);
robj *createStringObjectFromLongLongForValue(long long value);
robj *createStringObjectFromLongDouble(long double value, int humanfriendly);
robj *createQuicklistObject(void);
robj *createZiplistObject(void);
robj *createSetObject(void);
robj *createIntsetObject(void);
robj *createHashObject(void);
robj *createZsetObject(void);
robj *createZsetZiplistObject(void);
robj *createStreamObject(void);
robj *createModuleObject(moduleType *mt, void *value);

//对引用计数加1
void incrRefCount(robj *o) {
    if (o->refcount < OBJ_FIRST_SPECIAL_REFCOUNT) {
        o->refcount++;
    } else {
        if (o->refcount == OBJ_SHARED_REFCOUNT) {
            /* Nothing to do: this refcount is immutable. */
        } else if (o->refcount == OBJ_STATIC_REFCOUNT) {
            serverPanic("You tried to retain an object allocated in the stack");
        }
    }
}
//对引用计数减1,减为0时释放对象内存
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--;
    }
}

        对象的整个生命周期可以划分为创建对象,操作对象,释放对象三个阶段。

二. 对象共享

        Redis除了用于实现引用计数内存回收机制之外,对象的引用计数属性还带由对象共享的作用。

        举个例子:假设键A创建一个包含整数值100的字符串对象作为值对象,如果这时键B也要创建一个同样保存了整数值100的字符串对象作为值对象。Redis服务器的做法是,让键A和键B共享同一个字符串对象。也就是将数据库的键的值指针指向一个现有的值对象,将共享的值对象的引用计数加一。

        这样的共享对象机制的作用是节约内存。 

        目前来说,Redis会在初始化服务器时,创建一万个字符串对象,这些对象包含从0到9999的所有整数值,当服务器需要用到值为0到9999的字符串对象时,服务器会使用到这些共享对象。而不是新创建对象。

        注意:创建共享字符串对象的数量可以通过redis.h/REDIS_SHARED_INTEGERS常量修改。

        下面的命令佐证了只有值是0到9999整数的字符串对象作为共享对象:

127.0.0.1:6379> set A 10000
OK
127.0.0.1:6379> OBJECT REFCOUNT A
(integer) 1
127.0.0.1:6379> set B 10000
OK
127.0.0.1:6379> OBJECT REFCOUNT A
(integer) 1
127.0.0.1:6379> OBJECT REFCOUNT B
(integer) 1

        另外,这些共享对象不单单只有字符串键可以使用,那些在数据结构嵌套了字符串对象的对象(linkedlist编码的列表对象,hashtable编码的哈希对象,hashtable编码的集合对象,zset编码的有序集合对象)都可以使用这些共享对象。

为什么Redis不包含字符串的对象:

        当服务器考虑将一个共享对象设置为键的值对象时,程序需要先检查给定的共享对象和键想创建的目标对象是否完全相同,只有在共享对象和目标对象完全相同的情况下,程序才会将共享对象用作键的值对象。当共享对象保存的值越复杂,验证共享对象和目标对象是否相同所需要的复杂度越高。

  • 假如共享对象是整数值的字符串对象,那么验证操作的复杂度为O(1)。
  • 假如共享对象是字符串值的字符串对象,那么验证操作复杂度为O(N)。
  • 假如共享对象是包含了多个值(或对象)的对象,比如列表对象或哈希对象,那么验证操作的复杂度将会是O(N^2)。

        因此,尽管共享对象可以节约内存,但是为了效率着想,Redis只对包含整数值的字符串对象进行共享。

三. 对象时间空转时长

        redisObject对象中还有一个属性lru,记录了对象最后一次被命令程序访问的时间。OBJECT IDLETIME命令可以打印出给定键的空转时长,这个空转时长就是通过将当前时间减去键的值对象的lru时间计算出来的。OBJECT IDLETIME命令在执行时不会修改lru属性。

        对象的空转时长出来可以使用OBJECT IDLETIME命令查看外,另外一个作用是:如果服务器打开了maxmemory选项,并且服务器的回收算法为volatile-lru或者allkeys-lru,那么当服务器占用的内存数超过maxmemory的值时,空转时长较高的那部分键会被服务器优先释放,从而回收内存。

   

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1302728.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024美赛备战2--模型建立(*****必看****)

建模 美赛涉及的建模知识范围非常广且深&#xff0c;纵观美赛真题不难发现&#xff0c;很多的模型 都是读研或者读博的时候才会真正深入开始研究&#xff0c;因此&#xff0c;对于做建模的同学来说&#xff0c; 是无法在赛前吃透大量模型的。推荐本科生分两个步骤去有效准备比赛…

2022年拉丁美洲中东和非洲医疗机器人市场及全球概况报告

今天分享的是机器人系列深度研究报告&#xff1a;《2022年拉丁美洲中东和非洲医疗机器人市场及全球概况报告》。 &#xff08;报告出品方&#xff1a;Apollo Reports&#xff09; 报告共计&#xff1a;195页 研究方法论 2.1通过桌面研究和内部存储库的假设 a)最初&#xff…

Python爬取酷我音乐

&#x1f388; 博主&#xff1a;一只程序猿子 &#x1f388; 博客主页&#xff1a;一只程序猿子 博客主页 &#x1f388; 个人介绍&#xff1a;爱好(bushi)编程&#xff01; &#x1f388; 创作不易&#xff1a;喜欢的话麻烦您点个&#x1f44d;和⭐&#xff01; &#x1f388;…

Docker入门指南:从基础到实践

在当今软件开发领域&#xff0c;Docker已经成为一种不可或缺的工具。通过将应用程序及其依赖项打包成轻量级的容器&#xff0c;Docker实现了开发、测试和部署的高度一致性。本文将深入研究Docker的基本概念&#xff0c;并通过详细的示例代码演示如何应用这些概念于实际场景中。…

【Qt开发流程】之UI风格、预览及QPalette使用

概述 一个优秀的应用程序不仅要有实用的功能&#xff0c;还要有一个漂亮美腻的外观&#xff0c;这样才能使应用程序更加友善、操作性良好&#xff0c;更加符合人体工程学。作为一个跨平台的UI开发框架&#xff0c;Qt提供了强大而且灵活的界面外观设计机制&#xff0c;能够帮助…

moviepy基本参数用法大全

阅读本文档的前置说明&#xff1a; 本文档用于讲解Python的moviepy库的自带函数的用法&#xff0c;主要目的是讲一下每个函数的每个参数的含义&#xff0c;无需一开始就全部掌握&#xff0c;粗略看一下就行&#xff0c;可以在后面自己开发过程&#xff0c;遇到不会用的函数再回…

[Linux基础知识]页表

文章目录 1.页表 环境变量2.进程 1.页表 环境变量 一个分页存储管理系统中&#xff0c;地址长度为 32 位&#xff0c;其中页号占 8 位&#xff0c;则页表长度是 页号即页表项的序号&#xff0c;总共占8个二进制位&#xff0c;意味着页表项的个数就是2^8 在CPU和物理内存之间进行…

Axure官方软件安装、汉化保姆级教程(带官方资源下载)

1.下载汉化包 百度云链接&#xff1a;https://pan.baidu.com/s/1lluobjjBZvitASMt8e0A_w?pwdjqxn 提取码&#xff1a; jqxn 2.解压压缩包 3.安装Axure 进行安装 点击next 打勾&#xff0c;然后next, 默认是c盘&#xff0c;修改成自己的文件夹&#xff08;不要什么都放c盘里…

STM32MP157D-DK1开发板固件烧录

本篇介绍STM32MP157D-DK1开发板如何烧录官方固件。 1 开发板基础硬件介绍 1.1 常用接口 板子上的各种接口功如下&#xff0c;本篇固件烧录&#xff0c;主要用的接口包括&#xff1a; CN6&#xff1a;供电接口B2&#xff1a;复位按键CN11&#xff1a;ST-LINK USB&#xff08…

STM32F407-14.1.0-01高级定时器简介

TIM1 和 TIM8 简介 高级控制定时器&#xff08;TIM1 和 TIM8&#xff09;包含一个 16 位自动重载计数器&#xff0c;该计数器由可编程预分频器驱动。 此类定时器可用于各种用途&#xff0c;包括测量输入信号的脉冲宽度&#xff08;输入捕获&#xff09;&#xff0c;或者生成输出…

WooCommerce商城个人微信支付网关 适合个人微信收款

点击获取WooCommerce商城个人微信支付网关 适合个人微信收款原文https://gplwp.eastfu.com/product/woocommerce-ge-ren-wei-xin-zhi-fu-wang-guan-shi-he-ge-ren/ 个人微信支付网关接口&#xff0c;无需提现&#xff0c;100%资金安全&#xff0c;官方清算&#xff0c;金额无限…

外包干了2年,技术退步明显...

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

Linux系统---基于Pipe实现一个简单Client-Server system

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、题目要求 Server是一个服务器进程&#xff0c;只能进行整数平方运算。Client要计算一个整数的平方的平方的平方&#xff0c;即…

【MATLAB】基于CEEMD分解的信号去噪算法(基础版)

代码的使用说明 【MATLAB】基于CEEMD分解的信号去噪算法&#xff08;基础版&#xff09; 代码流程图 代码效果图 获取代码请关注MATLAB科研小白的个人公众号&#xff08;即文章下方二维码&#xff09;&#xff0c;并回复CEEMD去噪 本公众号致力于解决找代码难&#xff0c;写代…

简单实现Spring容器(六) 实现AOP机制

阶段5: // 1.编写自己的Spring容器,实现扫描包,得到bean的class对象. // 2.扫描将 bean 信息封装到 BeanDefinition对象,并放入到Map. // 3.初始化单例池并完成getBean() createBean()方法 // 4.完成依赖注入(如果创建某个Bean对象,存在依赖注入,需要进行bean组装操作) // 5.b…

12.11QSS优化界面——对话框

完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如果账号和密码不匹配&#xf…

c语言为什么要引入变量

大家好&#xff0c;今天给大家介绍c语言为什么要引入变量&#xff0c;文章末尾附有分享大家一个资料包&#xff0c;差不多150多G。里面学习内容、面经、项目都比较新也比较全&#xff01;可进群免费领取。 C语言引入变量的原因主要是为了存储数据并且方便后续的操作和计算。 变…

深入解析C++中的虚函数和虚继承:实现多态性与继承关系的高级特性

这里写目录标题 虚函数虚函数实现动态绑定虚继承抽象类 虚函数 虚函数是在C中用于实现多态性的一种特殊函数。它通过使用关键字"virtual"进行声明&#xff0c;在基类中定义&#xff0c;可在派生类中进行重写。虚函数允许在运行时根据对象的实际类型来调用相应的函数…

FTR223限时回归?经典三花再加金翅膀,CL500特别款亮相

FTR223可以说是非常经典的一款本田小攀爬车型了&#xff0c;之前我还有幸玩过一段时间&#xff0c;最近本田在泰国车展上展出了CL500的特别版&#xff0c;其中FTR223纪念版的版画让人眼前一亮&#xff0c;经典的白、红、蓝三色搭配让人眼前一亮。 CL500这台车在国内今年刚上市&…

开关量防抖滤波器(梯形图和SCL源代码)

模拟量防抖超限报警功能块请查看下面文章链接: https://rxxw-control.blog.csdn.net/article/details/133969425https://rxxw-control.blog.csdn.net/article/details/133969425 1、开关量防抖滤波器 2、防抖滤波 3、梯形图代码