0

0

Redis的zmalloc函数实例分析

PHPz

PHPz

发布时间:2023-05-27 17:50:40

|

1411人浏览过

|

来源于亿速云

转载

我们直接来看 redis 源码(不是最新版本)中自定义的 zmalloc 函数,该函数与 malloc 等常规函数的使用方式完全一致,不同的在于其内部的具体实现细节。

Mall4j商城系统
Mall4j商城系统

Mall4j是一个基于spring boot、spring oauth2.0、mybatis、redis的轻量级、前后端分离、防范xss攻击、拥有分布式锁、为生产环境多实例完全准备、数据库为b2b2c设计、拥有完整sku和下单流程的java开源商城。

下载

void *zmalloc(size_t size) {

    // 分配内存;

    void *ptr = malloc(size + PREFIX_SIZE);

    // 分配失败抛出异常;

    if (!ptr) zmalloc_oom_handler(size);

// 系统是否可以使用”malloc_size“函数?

#ifdef HAVE_MALLOC_SIZE

    update_zmalloc_stat_alloc(zmalloc_size(ptr));

    return ptr;

#else

    // 在数据域保存分配数据的实际大小;

    *((size_t*)ptr) = size;

    // 计算对齐后的内存使用大小,并更新”used_memory“变量;

    update_zmalloc_stat_alloc(size + PREFIX_SIZE);

    // 返回数据体的初始位置;

    return (char*)ptr + PREFIX_SIZE;

#endif

}

其实,标准库中的 malloc 函数已经能够自动为分配的内存实现对齐,因此 zmalloc 方法在这里其主要目的是为了能够精确地计算每一次数据存储时所分配的内存大小。在每一次分配内存时,zmalloc 都会在该次分配的数据内存大小的基础上再加上一个 PREFIX_SIZE 大小的额外内存空间,这个 PREFIX_SIZE 宏代表了当前系统的最大内存寻址空间大小(size_t),其依赖于具体系统的类型不同而不同。这里我们可以简称这个 PREFIX_SIZE 大小的空间为一个存储单元的“数据头”部分。

初版 Redis 的存储单元结构

如上图所示,通过 *((size_t*)ptr) = size; 语句,Redis 在当前分配内存块的前 PREFIX_SIZE 个字节,即数据头内存储了本次实际分配的数据块大小,而在后面 ”size“ 大小的内存空间中才真正存放了二进制的数据实体。在这里名为 update_zmalloc_stat_alloc 的函数在其内部会维护一个名为 used_memory 的全局变量,该变量累加了每次新分配的内存大小。函数在最后返回了一个偏移的指针,指向了当前分配内存的数据体部分。update_zmalloc_stat_alloc 函数的具体实现细节如下。

#define update_zmalloc_stat_alloc(__n) do { 

    size_t _n = (__n); 

    // 手动内存补齐;

    if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); 

    atomicIncr(used_memory, __n); 

} while(0)

这里需要注意的重点是 _n += sizeof(long)-(_n&(sizeof(long)-1)); 这行语句。整个宏函数首先判断本次分配的内存大小是否为 sizeof(long) 大小的整数倍(64位机对应着8字节的内存对齐;32位机则对应着4字节的内存对齐),如果不是则通过我们之前给出的语句在该数据段后添加相应的占位空间来补足位数以满足内存对齐(4/8字节)的要求。最后的 atomicIncr 函数用来在保证线程安全的情况下更新全局的 used_memory 变量值。

而该版本 Redis 中内存释放与其内存分配的过程则正好相反。如下所示代码为对应 ”zfree“ 函数的实现细节。首先该函数通过 (char*)ptr-PREFIX_SIZE 语句(向内存低地址移动)指向了包含有该数据块实际占用大小的数据域首地址,然后通过 *((size_t*)realptr) 语句获得到了该数据块分配的真实内存大小(不包含内存对齐区域)。最后再通过 update_zmalloc_stat_free 函数来更新全局变量 used_memory 的值,并释放该段内存。

void zfree(void *ptr) {

#ifndef HAVE_MALLOC_SIZE

    void *realptr;

    size_t oldsize;

#endif

    if (ptr == NULL) return;

#ifdef HAVE_MALLOC_SIZE

    update_zmalloc_stat_free(zmalloc_size(ptr));

    free(ptr);

#else

    realptr = (char*)ptr-PREFIX_SIZE;

    oldsize = *((size_t*)realptr);

    update_zmalloc_stat_free(oldsize+PREFIX_SIZE);

    free(realptr);

#endif

}

如下所示,这里如果我们再来看 update_zmalloc_stat_free 函数的实现细节,你会发现它与之前的 update_zmalloc_stat_alloc 函数其执行过程类似。通过计算需要补足的内存字节大小,并从 used_memory 变量中减去相应大小的内存空间,即可实现对内存空间使用率的精确计算。

#define update_zmalloc_stat_free(__n) do { \

    size_t _n = (__n); \

    if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \

    atomicDecr(used_memory,__n); \

} while(0) 

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

231

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

435

2024.03.01

typedef和define区别
typedef和define区别

typedef和define区别在类型检查、作用范围、可读性、错误处理和内存占用等。本专题为大家提供typedef和define相关的文章、下载、课程内容,供大家免费下载体验。

107

2023.09.26

define的用法
define的用法

define用法:1、定义常量;2、定义函数宏:3、定义条件编译;4、定义多行宏。更多关于define的用法的内容,大家可以阅读本专题下的文章。

323

2023.10.11

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

722

2023.08.22

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

83

2023.09.25

全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

73

2025.09.18

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

96

2025.09.18

java学习网站推荐汇总
java学习网站推荐汇总

本专题整合了java学习网站相关内容,阅读专题下面的文章了解更多详细内容。

6

2026.01.08

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

相关下载

更多

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
进程与SOCKET
进程与SOCKET

共6课时 | 0.3万人学习

Redis+MySQL数据库面试教程
Redis+MySQL数据库面试教程

共72课时 | 6.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号