1. Redis内存管理通过在zmalloc.h和zmalloc.c中重写c语言对内存的管理来完成的。
定义平台之间的差异,主要是tcmalloc(google)、jemalloc(facebook)、苹果平台。
具体来说就是:
- 若系统中存在Google的TC_MALLOC库,则使用tc_malloc一族函数代替原本的malloc一族函数。
- 若系统中存在facebook的JE_MALLOC库,则使用je_malloc一族函数替换原来的malloc一族函数。
- 若当前系统是Mac系统或者其它系统,则使用
中的内存分配函数。
<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
具体如下:
<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实现
</span><span style="color: #0000ff;">if</span> (!<span style="color: #000000;">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;">return</span><span style="color: #000000;"> 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