Redis 内存分配及释放相关源码阅读笔记,源码文件 zmalloc.h
& zmalloc.c
。
1. 小结
- 封装
tcmalloc
,jemalloc
,libmalloc
,ptmalloc
或自定义内存管理,增加内存使用量统计,但由于并未计算内存补齐的原因,全局变量used_memory
一般小于实际分配内存大小 - 在使用针对 Redis 修改的特殊
jemalloc
时,才能启用 Redis 内存碎片整理功能
Tips
-
将 $a$ 调整为 $b = 2^n$ 的整数倍
1 2
if (a & (b-1)) a += b - (a & (b-1));
2. 分配内存
2.1. zmalloc
|
|
-
zmalloc_size
使用
tcmalloc
,jemalloc
,libmalloc
或ptmalloc
时,HAVE_MALLOC_SIZE
为 1不同内存分配函数的区别,可以参考这篇博客。
自身定义的
zmalloc_size
函数如下:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/* Provide zmalloc_size() for systems where this function is not provided by * malloc itself, given that in that case we store a header with this * information as the first bytes of every allocation. */ #ifndef HAVE_MALLOC_SIZE size_t zmalloc_size(void *ptr) { void *realptr = (char*)ptr-PREFIX_SIZE; size_t size = *((size_t*)realptr); /* Assume at least that all the allocations are padded at sizeof(long) by * the underlying allocator. (内存对齐) */ if (size&(sizeof(long)-1)) size += sizeof(long)-(size&(sizeof(long)-1)); return size+PREFIX_SIZE; } size_t zmalloc_usable(void *ptr) { return zmalloc_size(ptr)-PREFIX_SIZE; } #endif
-
update_zmalloc_stat_alloc
1 2 3 4 5 6
#define update_zmalloc_stat_alloc(__n) do { \ size_t _n = (__n); \ if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \ // atomicIncr(var,count) atomicIncr(used_memory,__n); \ } while(0)
根据 redis #4770,第 2、3 两行可以删除。目前由于并未计算内存补齐的原因,全局变量
used_memory
一般小于实际分配内存大小。
Tips: do {} while(0)
的作用:
- 辅助定义复杂的宏,避免引用的时候出错
- 避免使用
goto
对程序流进行统一的控制,例如:使用break
来代替goto
,后续的处理工作在while
之后,就能够达到同样的效果 - 避免空宏引起的
warning
- 定义一个单独的函数块来实现复杂的操作
Tips: 将 $a$ 调整为 $b = 2^n$ 的整数倍
|
|
2.2. zcalloc
源码逻辑和 zmalloc
一样,此处主要介绍 malloc
和 calloc
的区别:
Prototype | effect |
---|---|
void* malloc(size_t size); |
分配 size 字节未初始化的内存空间 |
void* calloc(size_t num, size_t size); |
为 num 个大小为 size 的对象分配内存空间,并且初始化每一 bit 为 0 |
两个函数都是线程安全的,并且都满足内存对齐,当分配成功时,返回指向初始位置的指针,该指针需要调用 free()
或 realloc()
释放,当分配失败时,返回空指针。
2.3. zrealloc
|
|
-
update_zmalloc_stat_free
1 2 3 4 5 6
#define update_zmalloc_stat_free(__n) do { \ size_t _n = (__n); \ if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \ // atomicDecr(var,count) atomicDecr(used_memory,__n); \ } while(0)
同上,根据 redis #4770,第 2、3 两行可以删除。
3. 释放内存
3.1. zfree
|
|
4. Utils
4.1. 复制字符串
|
|
4.2. 获取 used_memory
|
|
4.3. 设置异常处理函数
|
|