Redis现在的版本可以支持使用tcmalloc或者是jemalloc或是apple的malloc,或者是Redis自己的zmalloc。zmalloc对内存的分配管理是线程安全的(static size_t used_memory = 0;变量用来记录已经使用的内存空间的大小),而且分配的内存必须要求是以sizeof(long)对其的。
源码
zmalloc.hzmalloc.c
分析
zmalloc除了提供标准的zamlloc,zcalloc,zrealloc,zfree功能之外还提供了dump内存数据到字符串的函数zstrdup,获得已经使用的内存总量的zmalloc_used_memory函数以及设置内存溢出处理函数的zmalloc_set_oom_handler。同时还提供了用于获得系统中的RSS,即程序所占用的实际的物理内存大小。
-------------------------------------以上是转载。
/* Double expansion needed forstringification of macro values. */
#define __xstr(s) __str(s)
#define __str(s) #s
在注释中出现了一个专有名词“ stringification ”,经查阅,网络上比较认可的翻译是“字符串化”。所以上面双重宏定义的用途为“用于宏值字符串化的双重宏展开 ”。
中也对双重宏定义的用法进行了举例说明。针对 xstr(foo) 展开的情况,由于 xstr() 本身是一个符合普通宏展开定义的东东,而 foo 同样是这样的一个东东 ,所以,在对 xstr(foo) 进行宏展开的时,会按照正常的展开顺序进行,即先展开 foo,再展开 xstr 。
stringification :
Sometimes you may want to convert a macro argument into astring constant. Parameters are not replaced inside string constants, but youcan use the ‘
#’ preprocessing operator instead. When a macro parameter isused with a leading ‘#’, the preprocessor replaces it with the literal text ofthe actual argument, converted to a string constant. Unlike normal parameterreplacement, the argument is not macro-expanded first. This is calledstringification.
至于采用二级宏定义的好处,当然就是可以更加灵活的对宏展开时的内容进行控制。
#define __xstr(s) __str(s)
#define __str(s) #s
#define foo 4
Str(foo) ==》“foo”
Xstr(foo) èxstr(4)->str(4)->”4”
#definezmalloc_size(p) malloc_size(p)
void*zmalloc(size_t size);
void*zcalloc(size_t size);
void*zrealloc(void *ptr, size_t size);
void zfree(void*ptr);
调用相应的malloc realloc calloc并对used_memory进行处理
另外还加上对溢出(分配失败或释放失败)进行判断,并进行处理。
char*zstrdup(const char *s);
对char*类型的s的字符串,在堆空间上进行分配空间(strlen(s)+1),并复制s的内容到空间上。
size_tzmalloc_used_memory(void);
获取used_memory,这里used_memory是共享资源,必须先获取线程的互斥量锁。
voidzmalloc_enable_thread_safeness(void);
voidzmalloc_set_oom_handler(void (*oom_handler)(size_t));//内存溢出处理函数
默认的处理函数为打印出出错信息,之后abort()终止
floatzmalloc_get_fragmentation_ratio(size_t rss);
Fragmentation =RSS / allocated-bytes
size_tzmalloc_get_rss(void);
这个函数效率比较慢,RedisEstimateRSS()函数,这是一个快得多(不太准确)。
HAVE_PROC_STAT:读取/proc/pid/stat文件的内容。
HAVE_TASKINFO:task_for_pid() task_basic_info
其他:zmalloc_used_memory
size_tzmalloc_get_private_dirty(void);
HAVE_PROC_SMAPS:/proc/self/smaps
voidzlibc_free(void *ptr);
访问original libc free() libc运行库里的free()
我们需要定义这个函数在包含zmalloc.h之前,这样可以隐藏free实现,if we use jemalloc or another nonstandard allocator.
当使用tcmalloc重写malloc/free函数,
使用#define malloc(size) tc_malloc(size)
size_t _n =(__n); \
if (_n&(sizeof(long)-1)) _n +=sizeof(long)-(_n&(sizeof(long)-1)); \
这里需要_n为long的整数倍(如果不满足,则扩大_n的大小为long的整数倍)
static size_tused_memory = 0;
static intzmalloc_thread_safe = 0;
pthread_mutex_tused_memory_mutex = PTHREAD_MUTEX_INITIALIZER;//只对静态分配的互斥量进行初始化。
rss =strtoll(p,NULL,10);