Redis zmalloc模块
2020-12-03 本文已影响0人
突击手平头哥
Redis zmalloc模块
zmalloc是处理redis内存的模块,主要涉及文件有:zmalloc、zmalloc.h、atomicvar.h, 本文从几个函数入手,简单说明该模块;同时这里面兼容了没有很多系统版本,目前仅分析普通Linux下的情况
HAVE_MALLOC_SIZE宏定义
#if defined(USE_TCMALLOC)
#define ZMALLOC_LIB ("tcmalloc-" __xstr(TC_VERSION_MAJOR) "." __xstr(TC_VERSION_MINOR))
#include <google/tcmalloc.h>
#if (TC_VERSION_MAJOR == 1 && TC_VERSION_MINOR >= 6) || (TC_VERSION_MAJOR > 1)
#define HAVE_MALLOC_SIZE 1
#define zmalloc_size(p) tc_malloc_size(p)
#else
#error "Newer version of tcmalloc required"
#endif
这里截取了一部分,优先采用tmalloc、jmalloc最后才使用标准的malloc函数;对于tmalloc、jmalloc我们不做分析处理,这里就当作是普通系统的malloc来分析
zmalloc_size函数
Redis中有统计内存大小的需求, 而正常来说malloc会进行一定的4/8字节对齐,所以不能简单的计算;该函数是系统API计算堆上分配的内存
#define zmalloc_size(p) malloc_usable_size(p)
zmalloc
函数
void *zmalloc(size_t size) {
void *ptr = malloc(size+PREFIX_SIZE); //单独内存分配并没有做非常特殊的封装
if (!ptr) zmalloc_oom_handler(size); //可以忽略,只是在错误时打印错误并退出
#ifdef HAVE_MALLOC_SIZE
update_zmalloc_stat_alloc(zmalloc_size(ptr)); //累计已分配内存大小
return ptr;
#else
*((size_t*)ptr) = size; //兼容没有malloc_size的情况, 在头部加一个PREFIX_SIZE存储大小
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
return (char*)ptr+PREFIX_SIZE;
#endif
}
//因为malloc对齐的缘故, 所以累计大小时需要向上扩展到4/8的倍数
#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)
- 内部实际分配内存还是用的malloc
- 会将内存扩展到long大小的倍数(4/8), 并且记录下来;
(_n&(sizeof(long)-1))
就可以判断是否可以被sizeof(long)
整除了 - 使用
atomicIncr
累计, 具体实现稍后分析
zfree
函数
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
}
#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)
实现于zmalloc是类似的
atomicIncr
函数
顾名思义, 很简单就可以猜出是进行原子性加减的函数
.....
#define atomicIncr(var,count) __atomic_add_fetch(&var,(count),__ATOMIC_RELAXED)
.....
#define atomicIncr(var,count) __sync_add_and_fetch(&var,(count))
.....
#define atomicIncr(var,count) do { \
pthread_mutex_lock(&var ## _mutex); \
var += (count); \
pthread_mutex_unlock(&var ## _mutex); \
} while(0)
__sync_add_and_fetch
是gcc编译器提供的原子性操作,第一个没了解过;如果编译器或者系统未提供原子性操作,即使用锁来实现