[redis] zmalloc
一下的源码分析基于redis 7.0的版本
redis版本:7.0
zmalloc.h
zmalloc.c
zmalloc.h
malloc的逻辑是:如果我们配置了类似jemalloc这样的分配器,那么我们则不需要PREFIX_SIZE(在linux上=sizeof(long)),否则在分配的时候多分配PREFIX_SIZE字节用于存储该指针的大小,对于jemalloc这样的分配器来说,直接使用zmalloc_size(void *)接口即可知道该ptr指向内存的大小。这个大小会记录在used_memory这个全局变量中(多线程安全),内存序为memory_order_relaxed。
/* Allocate memory or panic */
void *zmalloc(size_t size) {
void *ptr = ztrymalloc_usable(size, NULL);
if (!ptr) zmalloc_oom_handler(size);
return ptr;
}
/* Try allocating memory, and return NULL if failed.
* '*usable' is set to the usable size if non NULL. */
void *ztrymalloc_usable(size_t size, size_t *usable) {
ASSERT_NO_SIZE_OVERFLOW(size);
void *ptr = malloc(MALLOC_MIN_SIZE(size)+PREFIX_SIZE);
if (!ptr) return NULL;
#ifdef HAVE_MALLOC_SIZE
size = zmalloc_size(ptr);
update_zmalloc_stat_alloc(size);
if (usable) *usable = size;
return ptr;
#else
*((size_t*)ptr) = size;
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
if (usable) *usable = size;
return (char*)ptr+PREFIX_SIZE;
#endif
}
// 登记redis使用了__n字节内存
#define update_zmalloc_stat_alloc(__n) atomicIncr(used_memory,(__n))
#define update_zmalloc_stat_free(__n) atomicDecr(used_memory,(__n))
// OOM的处理
static void zmalloc_default_oom(size_t size) {
fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n",
size);
fflush(stderr);
abort();
}
free
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) atomicDecr(used_memory,(__n))
free其实也比较简单,如果使用系统自带的malloc,那么则需要找到正确的ptr,就是传入的ptr减去PREFIX_SIZE,然后free即可。