深入redis内部--内存管理

1. Redis内存管理通过在zmalloc.h和zmalloc.c中重写c语言对内存的管理来完成的。

封装就是为了屏蔽底层平台的差异,同时方便自己实现相关的统计函数。

定义平台之间的差异,主要是tcmalloc(google)、jemalloc(facebook)、苹果平台。

具体来说就是:

  • 若系统中存在Google的TC_MALLOC库,则使用tc_malloc一族函数代替原本的malloc一族函数。
  • 若系统中存在facebook的JE_MALLOC库,则使用je_malloc一族函数替换原来的malloc一族函数。
  • 若当前系统是Mac系统或者其它系统,则使用中的内存分配函数。
__xstr(s) __str(s) __str(s) #s

<span style="color: #0000ff;">#if defined(USE_TCMALLOC)
<span style="color: #0000ff;">#define ZMALLOC_LIB ("tcmalloc-" xstr(TC_VERSION_MAJOR) "." xstr(TC_VERSION_MINOR))<span style="color: #000000;">

include <google/tcmalloc.h>

<span style="color: #0000ff;">#if (TC_VERSION_MAJOR == 1 && TC_VERSION_MINOR >= 6) || (TC_VERSION_MAJOR > 1)
<span style="color: #0000ff;">#define HAVE_MALLOC_SIZE 1
<span style="color: #0000ff;">#define zmalloc_size(p) tc_malloc_size(p)
<span style="color: #0000ff;">#else
<span style="color: #0000ff;">#error "Newer version of tcmalloc required"
<span style="color: #0000ff;">#endif

<span style="color: #0000ff;">#elif defined(USE_JEMALLOC)
<span style="color: #0000ff;">#define ZMALLOC_LIB ("jemalloc-" xstr(JEMALLOC_VERSION_MAJOR) "." xstr(JEMALLOC_VERSION_MINOR) "." __xstr(JEMALLOC_VERSION_BUGFIX))<span style="color: #000000;">

include <jemalloc/jemalloc.h>

<span style="color: #0000ff;">#if (JEMALLOC_VERSION_MAJOR == 2 && JEMALLOC_VERSION_MINOR >= 1) || (JEMALLOC_VERSION_MAJOR > 2)
<span style="color: #0000ff;">#define HAVE_MALLOC_SIZE 1
<span style="color: #0000ff;">#define zmalloc_size(p) je_malloc_usable_size(p)
<span style="color: #0000ff;">#else
<span style="color: #0000ff;">#error "Newer version of jemalloc required"
<span style="color: #0000ff;">#endif

<span style="color: #0000ff;">#elif defined(APPLE)<span style="color: #000000;">

include <malloc/malloc.h>

<span style="color: #0000ff;">#define HAVE_MALLOC_SIZE 1
<span style="color: #0000ff;">#define zmalloc_size(p) malloc_size(p)
<span style="color: #0000ff;">#endif

具体如下:

defined(USE_TCMALLOC) malloc(size) tc_malloc(size) calloc(count,size) tc_calloc(count,size) realloc(ptr,size) tc_realloc(ptr,size) free(ptr) tc_free(ptr) defined(USE_JEMALLOC) malloc(size) je_malloc(size) calloc(count,size) je_calloc(count,size) je_realloc(ptr,size) free(ptr) je_free(ptr) ifdef HAVE_ATOMIC

<span style="color: #0000ff;">#define update_zmalloc_stat_add(n) sync_add_and_fetch(&used_memory,(n))
<span style="color: #0000ff;">#define update_zmalloc_stat_sub(n) sync_sub_and_fetch(&used_memory,(__n))
<span style="color: #0000ff;">#else
<span style="color: #0000ff;">#define update_zmalloc_stat_add(
n) do { \<span style="color: #000000;">
pthread_mutex_lock(&<span style="color: #000000;">used_memory_mutex); \
used_memory +=<span style="color: #000000;"> (__n); \
pthread_mutex_unlock(&<span style="color: #000000;">used_memory_mutex); \
} <span style="color: #0000ff;">while(<span style="color: #800080;">0<span style="color: #000000;">)

<span style="color: #0000ff;">#define update_zmalloc_stat_sub(__n) do { \<span style="color: #000000;">
pthread_mutex_lock(&<span style="color: #000000;">used_memory_mutex); \
used_memory -=<span style="color: #000000;"> (__n); \
pthread_mutex_unlock(&<span style="color: #000000;">used_memory_mutex); \
} <span style="color: #0000ff;">while(<span style="color: #800080;">0<span style="color: #000000;">)

<span style="color: #0000ff;">#endif

说明:

Both libraries try to de-contention memory acquire by having threads pick the memory from different caches,but they have different strategies:


  • jemalloc (used by Facebook) maintains a cache per thread
  • tcmalloc (from Google) maintains a pool of caches,and threads develop a "natural" affinity for a cache,but may change

This led,once again if I remember correctly,to an important difference in term of thread management.


  • jemalloc is faster if threads are static,for example using pools
  • tcmalloc is faster when threads are created/destructed

1.1 zmalloc实现      

* *ptr = malloc(size+</span><span style="color: #0000ff;"&gt;if</span> (!<span style="color: #000000;"&gt;ptr) zmalloc_oom_handler(size); //如果没有发生内存溢出,则使用的分配方式static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;

ifdef HAVE_MALLOC_SIZE //HAVE_MALLOC_SIZE用来确定系统是否有函数malloc_size,定义如上所示。

update_zmalloc_stat_alloc(zmalloc_size(ptr)); //更新分配内存的状态。处理线程安全和线程不安全
</span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; ptr;

<span style="color: #0000ff;">#else
((size_t)ptr) =<span style="color: #000000;"> size;
update_zmalloc_stat_alloc(size+<span style="color: #000000;">PREFIX_SIZE);
<span style="color: #0000ff;">return (<span style="color: #0000ff;">char*)ptr+<span style="color: #000000;">PREFIX_SIZE;
<span style="color: #0000ff;">#endif<span style="color: #000000;">
}

<div class="cnblogs_code">

 update_zmalloc_stat_alloc(__n) do { \= (_n&(()-)) _n += ()-(_n&(()-+=(ifdef HAVE_ATOMIC

<span style="color: #0000ff;">#define update_zmalloc_stat_add(n) sync_add_and_fetch(&used_memory,(n))
<span style="color: #0000ff;">#else
<span style="color: #0000ff;">#define update_zmalloc_stat_add(__n) do { \<span style="color: #000000;">
pthread_mutex_lock(&<span style="color: #000000;">used_memory_mutex); \
used_memory +=<span style="color: #000000;"> (
n); \
pthread_mutex_unlock(&<span style="color: #000000;">used_memory_mutex); \
} <span style="color: #0000ff;">while(<span style="color: #800080;">0<span style="color: #000000;">)

<span style="color: #0000ff;">#define update_zmalloc_stat_sub(__n) do { \<span style="color: #000000;">
pthread_mutex_lock(&<span style="color: #000000;">used_memory_mutex); \
used_memory -=<span style="color: #000000;"> (__n); \
pthread_mutex_unlock(&<span style="color: #000000;">used_memory_mutex); \
} <span style="color: #0000ff;">while(<span style="color: #800080;">0<span style="color: #000000;">)

<span style="color: #0000ff;">#endif

说明

int pthread_mutex_lock(pthread_mutex_t *mutex);

当pthread_mutex_lock()返回时,该已被锁定。调用该函数让上锁,如果该已被另一个锁定和拥有,则调用该线程将阻塞,直到该互斥锁变为可用为止。

int pthread_mutex_unlock(pthread_mutex_t *mutex);和上面的函数为一对。

其它函数的实现类似。

相关文章

文章浏览阅读1.3k次。在 Redis 中,键(Keys)是非常重要的概...
文章浏览阅读3.3k次,点赞44次,收藏88次。本篇是对单节点的...
文章浏览阅读8.4k次,点赞8次,收藏18次。Spring Boot 整合R...
文章浏览阅读978次,点赞25次,收藏21次。在Centos上安装Red...
文章浏览阅读1.2k次,点赞21次,收藏22次。Docker-Compose部...
文章浏览阅读2.2k次,点赞59次,收藏38次。合理的JedisPool资...