redis——内存概述

Redis通过自己的方法管理内存,,主要方法有zmalloc(),zrealloc(), zcalloc()和zfree(), 分别对应C中的malloc(), realloc()、
calloc()和free()。相关代码在zmalloc.h和zmalloc.c中。
Redis自己管理内存的好处主要有两个:可以利用内存池等手段提高内存分配的性能;可以掌握更多的内存信息,以便于Redis虚拟内存(VM)等功能中,决定何时将数据swap到磁盘。
先回忆各个系统中常见的内存分配函数:
malloc()分配一块指定大小的内存区域,并返回指向区域开头的指针,若分配失败,则返回NULL。
calloc()与malloc()一样,分配一块指定大小的内存区域,成功时返回区域头指针,失败返回NULL。

区别在于, calloc()的输入参数为count和size,即分配的项的数
目,及每一项的大小。

calloc()在成功分配内存空间后,会将空间内所有值置0。
realloc()修改已分配的内存块的大小。若已分配的内存块后没有足够的空间用于扩展内存块,则重新申请一块满足需要的内存块,并将旧的数据拷贝到新位置,释放旧的内存块,返回指向新的内存块的指针;否则直接扩展原有的内存块。若分配失败,返回NULL。
free()释放已分配的内存块。
内存分配
在Redis中,如果系统中包含TCMALLOC,则会使用tc_malloc()等TCMALLOC中的方法代替malloc()等原有的分配内存方法。 TCmalloc是google perftools中的一个组件。

#if defined(USE_TCMALLOC)
#define malloc(size) tc_malloc(size)

首先看zmalloc()和zfree()两个最常用的方法。 Redis在申请内存时,除了申请需要的size外,还会多申请一块定长(PREFIX_SIZE)的区域用于记录所申请的内存块的长度。如果申请成功, Redis会使用宏函数(Redis中为性能考虑,大量使用宏函数)
update_zmalloc_stat_alloc(size+PREFIX_SIZE, size)记录申请的内存块的相关信息,以便监控内存使用状况;当内存块被zfree()释放时,根据头部的信息可以快速地获知被释放的内存区域的长度,然后通过宏函数update_zmalloc_stat_free()标记释放。源代码中,若系统支持malloc_size()方法,则会使用它返回指针所指向的内存块的大小(Mac OS X 10.4以上支持该方法[3])。 有疑惑的是,在支持malloc_size()的系统中,为何还要多申请PREFIX_SIZE的内存?
 

void *zmalloc(size_t size) {void *ptr = malloc(size+PREFIX_SIZE);if (!ptr) zmalloc_oom(size);
#ifdef HAVE_MALLOC_SIZEupdate_zmalloc_stat_alloc(redis_malloc_size(ptr),size);return ptr;
#else*((size_t*)ptr) = size; // 在头部记录内存块的长度update_zmalloc_stat_alloc(size+PREFIX_SIZE,size);return (char*)ptr+PREFIX_SIZE;
#endif
}

宏update_zmalloc_stat_alloc()中,首先将要分配的空间与内存对齐,然后会根据宏zmalloc_thread_safe判断是否需要对内存信息记录表的相关操作加锁。虽然Redis在大部分场景中是单线程读写的,即thread_safe的,但启用虚拟内存(VM),或持久化dump到磁盘等操作时会启动多线程,因此在多线程模式中,需要对部分操作加锁。内存监控
used_memory记录了Redis使用的内存总数。而多线程下malloc()是线程安全的。
zmalloc_allocations[]记录了各个size分配的内存块的数目,大于256个字节的按256算。应用程序可以通过zmalloc_allocations_for_size(size)获得对应size的
内存块的分配数目;也可以通过zmalloc_used_memory()获得Redis占用的总内存。这些监控类的方法在Redis的日志系统中被用到。
zcalloc(size)、 zrealloc()与zmalloc()的处理策略类似,不再详述。
在部分操作系统中, Redis可以通过zmalloc_get_rss()方法获得自己的进程占用
的内存信息。该信息通过操作系统提供,往往比Redis自己记录的used_memory更准确,
但其获取速度也较慢。这些信息也是用于虚拟内存功能。
除了内存相关的操作外, Redis在此还提供了一个复制字符串的方法zstrdup(char
*),该方法将申请一块与源字符串长度相同的内存区域,并用memcpy()拷贝字符串的内
容。
 

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

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

相关文章

Windows下如何用C语言清空特定文件夹中的所有文件

#include "iostream.h" //由于该博客系统发布是不能显示正常,代码如需调试,只需将改成""即可 #include "string.h" #include "stdlib.h" #include "time.h" #include "math.h" #include…

MachineLearning(5)-去量纲:归一化、标准化

去量纲:归一化、标准化1.归一化(Normalization)1.1 Min-Max Normalization1.2 非线性Normalization2.标准化(Standardlization)2.1 Z-score Normalization3.标准化在梯度下降算法中的重要性本博文为葫芦书《百面机器学习》阅读笔记。去量纲化 可以消除特征之间量纲的…

GDB调试技术(一)

启动GDB的方法有以下几种: 1、gdb <program> program也就是你的执行文件,一般在当然目录下。 2、gdb <program> core 用gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件。 3、

GDB调试技术(二)

1) 恢复程序运行和单步调试 当程序被停住了,你可以用continue命令恢复程序的运行直到程序结束,或下一个断点到来。也可以使用step或next命令单步跟踪程序。 continue [ignore-count] c [ignore-count] fg [ignore-count] 恢复程序运行,直到程序结束,或是下一个断点到…

关于Java中String的问题

String 对象的两种创建方式&#xff1a; String str1 "abcd";//先检查字符串常量池中有没有"abcd"&#xff0c;如果字符串常量池中没有&#xff0c;则创建一个&#xff0c;然后 str1 指向字符串常量池中的对象&#xff0c;如果有&#xff0c;则直接将 st…

学点数学(3)-函数空间

函数空间1.距离&#xff1a;从具体到抽象2.范数3.内积4.拓扑本博文为观看《上海交通大学公开课-数学之旅-函数空间 》所整理笔记&#xff0c;公开课视频连接&#xff1a;http://open.163.com/newview/movie/free?pidM8PTB0GHI&midM8PTBUHT0数学中的空间 是 大家研究工作的…

Makefile编写详解--项目开发

预备知识&#xff1a; gcc 的3个参数&#xff1a; 1. -o 指定目标文件 gcc sources/main.c -o bin/main 2. -c 编译的时候只生产目标文件不链接 gcc -c sources/main.c -o obj/main.o 3. -I 主要指定头文件的搜索路径 gcc -I headers -c main.c -o main.o 4. -l 指定静…

如何判断对象已经死亡

引用计数 给对象中添加一个引用计数器&#xff0c;每当有一个地方引用它&#xff0c;计数器就加 1&#xff1b;当引用失效&#xff0c;计数器就减 1&#xff1b;任何时候计数器为 0 的对象就是不可能再被使用的。 这个方法实现简单&#xff0c;效率高&#xff0c;但是目前主流…

XML常见的操作

1. 创建XML文档 &#xff08;1&#xff09;创建一个XML文档非常简单&#xff0c;其流程如下&#xff1a; ① 用xmlNewDoc函数创建一个文档指针doc。 ② 用xmlNewNode函数创建一个节点指针root_node。 ③ 用xmlDocSetRootElement将root_node设置为doc的根结点。…

算法(2)-二叉树的遍历(递归/迭代)python实现

二叉树的遍历1.深度优先DFS1.1 DFS 递归解法1.1.1先序遍历1.1.2中序遍历1.1.3后序遍历1.2 DFS迭代解法1.2.1先序遍历1.2.2中序遍历1.2.3后序遍历2.广度优先BFS3.二叉树的最大深度3.1递归3.2迭代4.翻转二叉树4.1递归4.1迭代5.合并两棵二叉树5.1递归5.2迭代有两种通用的遍历树的策…

libxml的安装和相关数据结构详解

1安装 一般如果在安装系统的时候选中了libxml开发库的话&#xff0c;系统会默认安装。如果没有安装&#xff0c;可以按如下步骤进行手工安装。 ① 从xmlsoft站点或ftp(ftp.xmlsoft.org)站点下载libxml压缩包 (libxml2-xxxx.tar.gz) ② 对压缩包进行解压缩 tar xvzf …

内核中的 likely() 与 unlikely()

在 2.6 内核中&#xff0c;随处可以见到 likely() 和 unlikely() 的身影&#xff0c;那么为什么要用它们&#xff1f;它们之间有什么区别&#xff1f; 首先要明确&#xff1a; if(likely(value)) 等价于 if(value) if(unlikely(value)) 也等价于 if(value) 也就是说 likely()…

python外卷(12)-sort(),sorted(),ord(),chr()

Python内置函数1.sort()&#xff0c;sorted()2.ord(), chr()1.sort()&#xff0c;sorted() sort() 是list的方法&#xff0c;对已经存在的列表进行操作&#xff0c;无返回值 a[3,2,4,1] b["c","a","b"] print (a.sort(),b.sort()) # 输出 (Non…

利用posix_fadvise清理系统中的文件缓存

利用posix_fadvise清理系统中的文件缓存leoncom c/c,unix2011-08-03当我们需要对某段读写文件并进行处理的程序进行性能测试时&#xff0c;文件会被系统cache住从而影响I/O的效率&#xff0c;必须清理cache中的对应文件的才能正确的进行性能测试。通常清理内存可以采用下面的这…

空间分配

目前主流的垃圾收集器都会采用分代回收算法&#xff0c;因此需要将堆内存分为新生代和老年代&#xff0c;这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。 大多数情况下&#xff0c;对象在新生代中 eden 区分配。当 eden 区没有足够空间进行分配时&#xff0c;虚拟…

关于uint32_t uint8_t uint64_t 的问题

怎么又是u又是_t的?u代表的是unsigned相信大家都知道,那么_t又是什么呢?我认为它就是一个结构的标注,可以理解为type/typedef的缩写,表示它是通过typedef定义的,而不是其它数据类型。 uint8_t,uint16_t,uint32_t等都不是什么新的数据类型,它们只是使用typedef给类型起…

学点数学(4)-协方差矩阵

协方差矩阵协方差矩阵&#xff08;从随机变量讲起&#xff09;随机变量x&#xff1a;表示随机试验各种结果的 实值 单值函数&#xff0c;就是说随机变量x是一个函数映射&#xff0c;其取值为标量。随机变量有离散型和连续型&#xff0c;离散型&#xff1a;抛10次硬币&#xff…

RedLock

概念 Redis 官方站这篇文章提出了一种权威的基于 Redis 实现分布式锁的方式名叫 Redlock&#xff0c;此种方式比原先的单节点的方法更安全。它可以保证以下特性&#xff1a; 安全特性&#xff1a;互斥访问&#xff0c;即永远只有一个 client 能拿到锁避免死锁&#xff1a;最终…

GCC中常用的优化的参数

-pipe 的作用&#xff1a; 使用管道代替编译中临时文件&#xff0c; -pipe 加速编译 gcc -pipe foo.c -o foo 加速 在将源代码变成可执行文件的过程中,需要经过许多中间步骤,包含预处理、编译、汇编和连接。这些过程实际上是由不同的程序负责完成的。大多数情况下 GCC 可以为 …

Linux与时间相关的结构体及相关用法

1. Linux下与时间有关的结构体 struct timeval { int tv_sec; int tv_usec; }; 其中tv_sec是由凌晨开始算起的秒数&#xff0c;tv_usec则是微秒(10E-6 second)。 struct timezone { …