Redis 内存分配及释放相关源码阅读笔记,源码文件 zmalloc.h & zmalloc.c。
1. 小结
- 封装
tcmalloc,jemalloc,libmalloc,ptmalloc或自定义内存管理,增加内存使用量统计,但由于并未计算内存补齐的原因,全局变量used_memory一般小于实际分配内存大小 - 在使用针对 Redis 修改的特殊
jemalloc时,才能启用 Redis 内存碎片整理功能
Tips
-
将 $a$ 调整为 $b = 2^n$ 的整数倍
1 2if (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_alloc1 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_free1 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. 设置异常处理函数
|
|