Redis数据库的内存管理函数有关的文件为:zmalloc.h和zmalloc.c。

Redis作者在编写内存管理模块时考虑到了查看系统内是否安装了TCMalloc或者Jemalloc模块,这两个是已经存在很久的内存管理模块,代码稳定、性能优异,如果已经安装的话,则使用之,最后检查是否是Mac系统,如果是Mac系统的话加载的文件不同,额,本人没进行过Mac编程,这块儿不考虑。对应的源代码为:

  1. //检查是否定义了TCMalloc,TCMalloc(Thread-Caching Malloc)与标准glibc库的malloc实现一样的功能,但是TCMalloc在效率和速度效率都比标准malloc高很多
  2. #if defined(USE_TCMALLOC)
  3. #define ZMALLOC_LIB ("tcmalloc-" __xstr(TC_VERSION_MAJOR) "." __xstr(TC_VERSION_MINOR))
  4. #include <google/tcmalloc.h>
  5.  
  6. #if (TC_VERSION_MAJOR == 1 && TC_VERSION_MINOR >= 6) || (TC_VERSION_MAJOR > 1)
  7. #define HAVE_MALLOC_SIZE 1
  8. #define zmalloc_size(p) tc_malloc_size(p)
  9. #else
  10. #error "Newer version of tcmalloc required"
  11. #endif
  12. //检查是否定义了jemalloc库
  13. #elif defined(USE_JEMALLOC)
  14. #define ZMALLOC_LIB ("jemalloc-" __xstr(JEMALLOC_VERSION_MAJOR) "." __xstr(JEMALLOC_VERSION_MINOR) "." __xstr(JEMALLOC_VERSION_BUGFIX))
  15. #include <jemalloc/jemalloc.h>
  16. #if (JEMALLOC_VERSION_MAJOR == 2 && JEMALLOC_VERSION_MINOR >= 1) || (JEMALLOC_VERSION_MAJOR > 2)
  17. #define HAVE_MALLOC_SIZE 1
  18. #define zmalloc_size(p) je_malloc_usable_size(p)
  19. #else
  20. #error "Newer version of jemalloc required"
  21. #endif
  22. //检查是否是苹果系统
  23. #elif defined(__APPLE__)
  24. #include <malloc/malloc.h>
  25. #define HAVE_MALLOC_SIZE 1/*标记已经找到了可用的现成函数库*/
  26. #define zmalloc_size(p) malloc_size(p)/*因为每个库的实现方式不一样,所以测试大小的函数也不一样*/
  27. #endif

 先整体说一下内存管理的所有接口函数,然后慢慢分析,所有的接口函数为:

  1. void *zmalloc(size_t size);//重写malloc函数,申请内存
  2. void *zcalloc(size_t size);//重写calloc函数,不再支持按块的成倍申请,内部调用的是zmalloc
  3. void *zrealloc(void *ptr, size_t size); //重写内存扩展函数
  4. void zfree(void *ptr); //重写内存释放函数,释放时会更新已使用内存的值,如果在多线程下没有开启线程安全模式,可能会出现并发错误。
  5. char *zstrdup(const char *s); //字符串持久化存储函数函数,为字符串在堆内分配内存。
  6. size_t zmalloc_used_memory(void); //获取已经使用内存大小函数。
  7. void zmalloc_enable_thread_safeness(void); //设置内存管理为多线程安全模式,设置之后在更新已使用内存大小时会用Mutex进行互斥操作。
  8. void zmalloc_set_oom_handler(void (*oom_handler)(size_t)); //设置内存异常时调用的函数。
  9. float zmalloc_get_fragmentation_ratio(size_t rss); //
  10. size_t zmalloc_get_rss(void); //获取进程可使用的所有内存大小。
  11. size_t zmalloc_get_private_dirty(void); //
  12. size_t zmalloc_get_smap_bytes_by_field(char *field);
  13. void zlibc_free(void *ptr); //释放指针指向内存函数,用这个释放内存时,不会更新使用内存变量的值。
  14. #ifndef HAVE_MALLOC_SIZE
  15.   size_t zmalloc_size(void *ptr); //获取内存块总题大小函数。
  16. #endif

在解析函数的详细实现前,先分析一下.c文件开始所做的处理。在.c文件中定义了三个变量,一个用来记录已经使用内存的大小,一个用来记录是否开启了多线程安全模式,一个是互斥锁。

  1. static size_t used_memory = 0;/*记录已经使用碓内存的大小*/
  2. static int zmalloc_thread_safe = 0;/*是否开启了线程安全*/
  3. pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;/*互斥锁,如果开启了多线程安全,而编译器又不支持原子操作的函数,则需要用互斥锁来完成代码的互斥操作。*/

接下来要确定内存块前面是否需要加个头部,因为不能确定具体使用的到底是什么内存分配函数,TCMalloc或者Jemalloc库在申请的内存块前增加了一个小块的内存来记录该内存块的使用情况,因为本人没分析过着俩库,具体的不做分析,具体的代码为:

  1. #ifdef HAVE_MALLOC_SIZE//找到了已有的内存管理库时就会定义这个宏,如果已经定义了,则不再增加头部大小,如果没有定义,则根据具体的系统来确定增加头部大小的长度。
  2.   #define PREFIX_SIZE (0)//头部长度为0
  3. #else
  4.   #if defined(__sun) || defined(__sparc) || defined(__sparc__)
  5.     #define PREFIX_SIZE (sizeof(long long))//头部长度为longlong的大小
  6.   #else
  7.     #define PREFIX_SIZE (sizeof(size_t))//头部长度为size_tde的大小
  8.   #endif
  9. #endif

接下来是定义了两个更新内存占用变量的操作函数update_zmalloc_stat_add和update_zmalloc_stat_sub,这俩函数支持多线程。

  1. /*先检查编译器是否支持原子操作函数,如果支持的话,就不用互斥锁了,毕竟锁的效率很低。*/
  2. #if defined(__ATOMIC_RELAXED)//这个好像是C++11标准开始支持的,具体的不是很清楚
  3. #define update_zmalloc_stat_add(__n) __atomic_add_fetch(&used_memory, (__n), __ATOMIC_RELAXED)
  4. #define update_zmalloc_stat_sub(__n) __atomic_sub_fetch(&used_memory, (__n), __ATOMIC_RELAXED)
  5. #elif defined(HAVE_ATOMIC)//这个是GCC从某个版本开始支持的,不是所有版本的GCC都支持sync系列函数。
  6. #define update_zmalloc_stat_add(__n) __sync_add_and_fetch(&used_memory, (__n))
  7. #define update_zmalloc_stat_sub(__n) __sync_sub_and_fetch(&used_memory, (__n))
  8. #else//不支持原子操作的情况下只能使用互斥锁了。
  9. #define update_zmalloc_stat_add(__n) do { \
  10. pthread_mutex_lock(&used_memory_mutex); \
  11. used_memory += (__n); \
  12. pthread_mutex_unlock(&used_memory_mutex); \
  13. } while()
  14.  
  15. #define update_zmalloc_stat_sub(__n) do { \
  16. pthread_mutex_lock(&used_memory_mutex); \
  17. used_memory -= (__n); \
  18. pthread_mutex_unlock(&used_memory_mutex); \
  19. } while()
  20.  
  21. #endif
  22. //更新内存使用变量函数,函数内确定是否需要多线程安全
  23. #define update_zmalloc_stat_alloc(__n) do { \
  24. size_t _n = (__n); \
  25. if (_n&(sizeof(long)-)) _n += sizeof(long)-(_n&(sizeof(long)-)); \
  26. if (zmalloc_thread_safe) { \
  27. update_zmalloc_stat_add(_n); \
  28. } else { \
  29. used_memory += _n; \
  30. } \
  31. } while()
  32. //更新内存使用变量函数,函数内确定是否需要多线程安全
  33. #define update_zmalloc_stat_free(__n) do
  34. { \
  35.   size_t _n = (__n); \
  36.   if (_n&(sizeof(long)-)) _n += sizeof(long)-(_n&(sizeof(long)-)); \
  37.   if (zmalloc_thread_safe)
  38.   { \
  39.     update_zmalloc_stat_sub(_n); \
  40.   }
  41.   else
  42.   { \
  43.     used_memory -= _n; \
  44.   } \
  45. } while()

下一篇再写具体的函数实现。

Redis内存管理(一)的更多相关文章

  1. Redis 内存管理与事件处理

    1 Redis内存管理 Redis内存管理相关文件为zmalloc.c/zmalloc.h,其只是对C中内存管理函数做了简单的封装,屏蔽了底层平台的差异,并增加了内存使用情况统计的功能. void * ...

  2. Redis 内存管理 源码分析

    要想了解redis底层的内存管理是如何进行的,直接看源码绝对是一个很好的选择 下面是我添加了详细注释的源码,需要注意的是,为了便于源码分析,我把redis为了弥补平台差异的那部分代码删了,只需要知道有 ...

  3. Redis内存管理(二)

    上一遍详细的写明了Redis为内存管理所做的初始化工作,这篇文章写具体的函数实现. 1.zmalloc_size,返回内存池大小函数,因为库不同,所以这个函数在内部有很多的宏定义,通过具体使用的库来确 ...

  4. TCMalloc优化MySQL、Nginx、Redis内存管理

    TCMalloc(Thread-Caching Malloc)与标准glibc库的malloc实现一样的功能,但是TCMalloc在效率和速度效率都比标准malloc高很多.TCMalloc是 goo ...

  5. redis内存管理

    Redis主要通过控制内存上线和回收策略来实现内存管理. 1. 设置内存上限 redis使用maxmemory参数限制最大可用内存.限制的目的主要有: 用户缓存场景,当超出内存上限maxmemory时 ...

  6. Redis内存管理的基石zmallc.c源代码解读(一)

    当我第一次阅读了这个文件的源代码的时候.我笑了,忽然想起前几周阿里电话二面的时候,问到了自己定义内存管理函数并处理8字节对齐问题. 当时无言以对,在面试官无数次的提示下才答了出来,结果显而易见,挂掉了 ...

  7. 详解 Redis 内存管理机制和实现

    Redis是一个基于内存的键值数据库,其内存管理是非常重要的.本文内存管理的内容包括:过期键的懒性删除和过期删除以及内存溢出控制策略. 最大内存限制 Redis使用 maxmemory 参数限制最大可 ...

  8. redis内存管理代码的目光

    zmalloc.h /* zmalloc - total amount of allocated memory aware version of malloc() * * Copyright (c) ...

  9. redis 内存管理与数据淘汰机制(转载)

    原文地址:http://www.jianshu.com/p/2f14bc570563?from=jiantop.com 最大内存设置 默认情况下,在32位OS中,Redis最大使用3GB的内存,在64 ...

随机推荐

  1. Mahout 介绍

    1.Hbase+k-means  (G级别) 2.k-means+mr (T级别) 1. 2.canopy 2.贝叶斯算法 决策,分类,文档分类 3.推荐系统 4.图书推荐系统 1.需求 付完款的用户 ...

  2. 读取XML文件

    首先要确定好XML文件的位置,最好是放在程序的debug文件中,放在其他地方也可以,要写上绝对路径 using System; using System.Collections.Generic; us ...

  3. Ubuntu 14 如何打开 .chm格式文档?

    好多手册是.chm格式,Ubuntu是需要安装第三方软件才能打开.chm格式文档,操作方式如下: 到“软件中心” -> 搜索“xchm”,并安装 -> 右键某个.chm文档,选择“属性” ...

  4. 9.4用WebApi去连接外部认证服务

    原文链接:http://www.asp.net/web-api/overview/security/external-authentication-services VS2013和Asp.Net4.5 ...

  5. FineUI第十二天---锚点布局

    锚点布局的典型结构: <x:Panel Layout="Anchor" runat="server">              <Items ...

  6. Android Sqlite 数据库版本更新

      Android Sqlite 数据库版本更新 http://87426628.blog.163.com/blog/static/6069361820131069485844/ 1.自己写一个类继承 ...

  7. Java多线程基础知识(六)

    一. Java中的线程池 线程池的作用: 1. 降低资源消耗 2. 提高响应速度 3. 提高线程的可管理性 线程池处理流程: 1. 线程池判断核心线程池线程是否都在执行任务,如果不是,则创建一个新的工 ...

  8. CSU 1333 Funny Car Racing (最短路)

    题目链接: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1333 解题报告:一个图里面有n个点和m条单向边,注意是单向边,然后每条路开a秒关闭b秒 ...

  9. 对C++虚函数、虚函数表的简单理解

    一.虚函数的作用 以一个通用的图形类来了解虚函数的定义,代码如下: #include "stdafx.h" #include <iostream> using name ...

  10. Codeforces Gym 101138 G. LCM-er

    Description 在 \([a,b]\) 之间选择 \(n\) 个数 (可以重复) ,使这 \(n\) 个数的最小公倍数能被 \(x\) 整除,对 \(10^9+7\) 取膜. \(1\leqs ...