redis 内存管理zmalloc
来源:互联网 发布:人民日报图文数据库 编辑:程序博客网 时间:2024/06/07 14:00
redis封装的内部结构,脑子里要有这幅图,就差不多了。实际分配的内存比size要多。
redis的zmalloc函数
// 已经使用的内存,malloc函数增加,free减少这个值static size_t used_memory = 0;// 线程安全,其实没用;redis是单线程模型static int zmalloc_thread_safe = 0;// used_memory变量作为临界区,做同步pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER;// 默认内存溢出handlerstatic void zmalloc_default_oom(size_t size) {// 打印日志 fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n", size);// 还是打印日志,到哪里 TODO fflush(stderr);// TODO abort();}static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom;void *zmalloc(size_t size) { void *ptr = malloc(size+PREFIX_SIZE);// 如果申请失败,一定是OOM if (!ptr) zmalloc_oom_handler(size);#ifdef HAVE_MALLOC_SIZE// 统计用计数器增增加 update_zmalloc_stat_alloc(zmalloc_size(ptr)); return ptr;#else// 使用4个字节记录申请内存字节数 *((size_t*)ptr) = size; update_zmalloc_stat_alloc(size+PREFIX_SIZE);// 返回实际内存指针 return (char*)ptr+PREFIX_SIZE;#endif1 首先把和多线程相关的去掉,先忽略。
2 HAVE_MALLOC_SIZE是什么意思zmalloc_size 内容是什么?
http://www.petermao.com/redis/78.html 这篇文章 对 HAVE_MALLOC_SIZE 有一行注释,“另外对于 apple系统,可以用malloc_size(redis_malloc_size是对它的封装)取得指针所指向的内存块大小,因此就不需要手动保存大小了。” 据此明了,redis 实现了类似apple的功能,使用申请的内存的前一段PREFIX_SIZE,保存真正申请(可以使用)的内存字节数。
zmalloc_size函数的注释,对于一些不支持zmalloc_size的系统这种情况,redis在每次分配内存的时候使用前几个字节保存实际使用的字节数。
/* 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_SIZEsize_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;}#endif
3 PREFIX_SIZE 记录一次分配内存,使用内存的字节数,他的大小怎么定义的?
http://blog.csdn.net/jinjinstudy/article/details/18189567
PREFIX_SIZE用来记录malloc已分配到的内存大小
tc_malloc/je_malloc/Mac平台分别采用tc_malloc_size/malloc_size/je_malloc_usable_size(不需要单独开空间计算得到的内存大小,PREFIX_SIZE值置为0)
linux和sun平台分别采用sizeof(size_t)=8字节和sizeof(long long)定长字段记录,所以要记录分配空间的大小
#ifdef HAVE_MALLOC_SIZE #define PREFIX_SIZE (0)#else #if defined(__sun) || defined(__sparc) || defined(__sparc__) #define PREFIX_SIZE (sizeof(long long)) #else #define PREFIX_SIZE (sizeof(size_t)) #endif#endif
简单来讲,可以把PREFIX_SIZE看作一个size_t的大小(一般是8字节)。它的主要作用是来记录本次分配的内存空间大小。对于不同平台来说,PREFIX_SIZE的值是不同的。
- 如果平台内存分配策略,已经使用前几个字节记录大小(HAVE_MALLOC_SIZE),PREFIX_SIZE = 0就不用再额外申请内存。
- 如果是sun的服务器,则分配一个8个字节当前缀 sizeof(long long)。
- 其他的使用size_t的大小8个字节。
/* 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));例如 size = 15 ,二进制表示 11111,sizeof(long) - 1 = 7,二进制表示111, 按位与15 & 7,结果是111,不等于0;所以,size +=
8 - 7,结果是16.
5 当使用tcmalloc库/jemalloc库的时候,显式覆盖malloc/calloc/realloc/free的方法
/* Explicitly override malloc/free etc when using tcmalloc. */#if defined(USE_TCMALLOC)#define malloc(size) tc_malloc(size)#define calloc(count,size) tc_calloc(count,size)#define realloc(ptr,size) tc_realloc(ptr,size)#define free(ptr) tc_free(ptr)#elif defined(USE_JEMALLOC)#define malloc(size) je_malloc(size)#define calloc(count,size) je_calloc(count,size)#define realloc(ptr,size) je_realloc(ptr,size)#define free(ptr) je_free(ptr)#endif6 增加内存和释放内存时used_memory计数器
#if defined(__ATOMIC_RELAXED)// 平台相关define#define update_zmalloc_stat_add(__n) __atomic_add_fetch(&used_memory, (__n), __ATOMIC_RELAXED)#define update_zmalloc_stat_sub(__n) __atomic_sub_fetch(&used_memory, (__n), __ATOMIC_RELAXED)#elif defined(HAVE_ATOMIC)// 平台相关define#define update_zmalloc_stat_add(__n) __sync_add_and_fetch(&used_memory, (__n))#define update_zmalloc_stat_sub(__n) __sync_sub_and_fetch(&used_memory, (__n))#else// 已使用内存 增加delta#define update_zmalloc_stat_add(__n) do { \ pthread_mutex_lock(&used_memory_mutex); \ used_memory += (__n); \ pthread_mutex_unlock(&used_memory_mutex); \} while(0)// 只执行一次// 已使用内存 减少delta#define update_zmalloc_stat_sub(__n) do { \ pthread_mutex_lock(&used_memory_mutex); \ used_memory -= (__n); \ pthread_mutex_unlock(&used_memory_mutex); \} while(0)#endif#define update_zmalloc_stat_alloc(__n) do { \ size_t _n = (__n); \// 内存对齐 if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \ if (zmalloc_thread_safe) { \// 多线程case使用 update_zmalloc_stat_add(_n); \ } else { \ used_memory += _n; \ } \} while(0)#define update_zmalloc_stat_free(__n) do { \ size_t _n = (__n); \// 内存对齐 if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \ if (zmalloc_thread_safe) { \ update_zmalloc_stat_sub(_n); \ } else { \ used_memory -= _n; \ } \} while(0)
7 calloc函数,他和malloc有什么不同?
void *zcalloc(size_t size) { void *ptr = calloc(1, 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; update_zmalloc_stat_alloc(size+PREFIX_SIZE); return (char*)ptr+PREFIX_SIZE;#endif}
http://blog.csdn.net/firecityplans/article/details/4490124/
void *malloc(unsigned size)//动态申请size个字节的内存空间;功能:在内存的动态存储区中分配一块长度为" size" 字节的连续区域。函数的返回值为该区域的首地址。。(类型说明符*)表示把返回值强制转换为该类型指针。
(void *)calloc(unsigned n,unsigned size)// 用于向系统动态申请n个, 每个占size个字节的内存空间; 并把分配的内存全都初始化为零值。函数的返回值为该区域的首地址
(void *)realloc(void *p,unsigned size)//将指针p所指向的已分配内存区的大小改为size
区别:两者都是动态分配内存。主要的不同是malloc不初始化分配的内存,已分配的内存中可以是任意的值. calloc 初始化已分配的内存为0。次要的不同是calloc返回的是一个数组,而malloc返回的是一个对象。
8 zrealloc 函数。realloc的功能是先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。
/** 重新分配内存;外部传入的指针地址是字符串地址;*/void *zrealloc(void *ptr, size_t size) {#ifndef HAVE_MALLOC_SIZE // ptr - PREFIX_SIZE 的地址 void *realptr;#endif size_t oldsize; void *newptr;// 如果ptr == null,重新分配一段内存 if (ptr == NULL) return zmalloc(size);#ifdef HAVE_MALLOC_SIZE oldsize = zmalloc_size(ptr); newptr = realloc(ptr,size); if (!newptr) zmalloc_oom_handler(size); update_zmalloc_stat_free(oldsize); update_zmalloc_stat_alloc(zmalloc_size(newptr)); return newptr;#else realptr = (char*)ptr-PREFIX_SIZE; oldsize = *((size_t*)realptr); newptr = realloc(realptr,size+PREFIX_SIZE); if (!newptr) zmalloc_oom_handler(size); *((size_t*)newptr) = size; update_zmalloc_stat_free(oldsize); update_zmalloc_stat_alloc(size);// 返回值是真正使用的字符串地址 return (char*)newptr+PREFIX_SIZE;#endif}
补说明,realloc函数的说明
realloc(void *__ptr, size_t __size):更改已经配置的内存空间,即更改由malloc()函数分配的内存空间的大小。
如果将分配的内存减少,realloc仅仅是改变索引的信息。
如果是将分配的内存扩大,则有以下情况:
1)如果当前内存段后面有需要的内存空间,则直接扩展这段内存空间,realloc()将返回原指针。
2)如果当前内存段后面的空闲字节不够,那么就使用堆中的第一个能够满足这一要求的内存块,将目前的数据复制到新的位置,并将原来的数据块释放掉,返回新的内存块位置。
3)如果申请失败,将返回NULL,此时,原来的指针仍然有效。
注意:如果调用成功,不管当前内存段后面的空闲空间是否满足要求,都会释放掉原来的指针,重新返回一个指针,虽然返回的指针有可能和原来的指针一样,即不能再次释放掉原来的指针。
9 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}
10 函数 获取已使用内存量,有并发的场景,前后加锁。
size_t zmalloc_used_memory(void) { size_t um; if (zmalloc_thread_safe) {#if defined(__ATOMIC_RELAXED) || defined(HAVE_ATOMIC) um = update_zmalloc_stat_add(0);#else pthread_mutex_lock(&used_memory_mutex); um = used_memory; pthread_mutex_unlock(&used_memory_mutex);#endif } else { um = used_memory; } return um;}
参考:
http://blog.csdn.net/guodongxiaren/article/details/44747719
http://blog.csdn.net/guodongxiaren/article/details/44783767
- redis 内存管理zmalloc
- Redis中的内存管理:关于zmalloc
- Redis源代码分析之一:内存管理——Zmalloc
- 菜鸟学习redis-----内存管理之zmalloc函数
- 【redis源码分析】内存分配---zmalloc
- Redis zmalloc
- redis zmalloc
- Redis源码分析(二十五)--- zmalloc内存分配实现
- Redis源码分析(二十五)--- zmalloc内存分配实现
- Redis中的zmalloc
- redis之zmalloc
- (redis)zmalloc.h/zmalloc.c理解
- 结合redis设计与实现的redis源码学习-1-内存分配(zmalloc)
- redis源码解读之内存管理————zmalloc文件
- zmalloc 代码解释(redis代码阅读)
- Redis 源码分析(zmalloc部分)
- Redis 源码阅读笔记1:zmalloc
- 编译安装redis报错zmalloc.h
- BlockingQueue的使用
- poj3250翻译+题解(单调栈)
- python爬虫学习第二十天
- 二进制1的个数(剑指Offer)
- 自下而上的编程
- redis 内存管理zmalloc
- React-navigation 官方文档中文翻译(四) intro to Navigators
- Linux下的进程和作业概念,以及作业管理
- 博科光交详解
- java小程序数组版电话本1.0版本(有问题尚未解决)
- poj2559Largest Rectangle in a Histogram
- win 10 主题 美化
- 并查集的定义及实现
- FreeMarker学习指南媲美JSP的优秀可视化技术