持续更新中…
zmalloc.c源码阅读笔记
源码内容
主要函数 | 功能简述 |
---|---|
zmalloc() | 分配内存,但不初始化 |
zfree() | 清理zmalloc()分配的内存 |
zcalloc() | 分配内存,并初始化为0 |
zrelloc() | 重新分配内存 |
zstrdup() | 字符串复制 |
主要宏 | 功能简述 |
---|---|
#define PREFIX_SIZE (sizeof(size_t)) | 在Linux中sizeof(size_t)其值是8个字节 |
#define update_zmalloc_stat_alloc(__n) | 字节对齐、判断线程环境是否安全,维护全局已分配内存数量的增加 |
#define update_zmalloc_stat_free(__n) | 字节对齐、判断线程环境是否安全,维护全局已分配内存数量的减少 |
其他函数 | 功能简述 |
---|---|
zmalloc_default_oom() | 用于报错 |
其他宏 | 功能简述 |
---|---|
#define update_zmalloc_stat_add(__n) | 使用线程安全方式为系统已分配内存(全局变量)增加n |
#define update_zmalloc_stat_sub(__n) | 使用线程安全方式为系统已分配内存(全局变量)减少n |
宏源码分析
update_zmalloc_stat_alloc() & update_zmalloc_stat_free()
do{
...
}while(0)
//这种代码风格的作用可以参考如下博客
链接:do{…}while(0)的意义和用法
#define update_zmalloc_stat_alloc(__n) do { \
size_t _n = (__n); \
//用于字节对齐
//等价于 if(_n&7) _n += 8 - (_n&7);
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
//检查线程环境是否安全
if (zmalloc_thread_safe) { \
update_zmalloc_stat_add(_n); \
} else { \
//安全时使用
used_memory += _n; \
} \
} while(0)
#define update_zmalloc_stat_free(__n) do { \
size_t _n = (__n); \
//用于字节对齐
//等价于 if(_n&7) _n += 8 - (_n&7);
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)
update_zmalloc_stat_add() & update_zmalloc_stat_sub()
确保线程安全,加了个线程锁。
#define update_zmalloc_stat_add(__n) do { \
pthread_mutex_lock(&used_memory_mutex); \
used_memory += (__n); \
pthread_mutex_unlock(&used_memory_mutex); \
} while(0)
#define update_zmalloc_stat_sub(__n) do { \
pthread_mutex_lock(&used_memory_mutex); \
used_memory -= (__n); \
pthread_mutex_unlock(&used_memory_mutex); \
} while(0)
函数源码分析
zmalloc()
void *zmalloc(size_t size) {
void *ptr = malloc(size+PREFIX_SIZE);//分配了一段8+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
}
zcalloc()
void *zcalloc(size_t size) {
void *ptr = calloc(1, size+PREFIX_SIZE);//有效部分唯一区别于zmalloc()的语句
/*
void *calloc(size_t nmemb, size_t size);
分配nmemb*size字节的内存并初始化为0
*/
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
}
zrealloc()
给ptr开始的内存空间重新分配size大小的空间,若失败就在其他位置新建一块大小为size字节的空间,并将原先的数据复制过去。原内存会
void *zrealloc(void *ptr, size_t size) {
#ifndef HAVE_MALLOC_SIZE
void *realptr;
#endif
size_t oldsize;
void *newptr;
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);
//zrealloc()实际上调用了realloc()函数
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
}
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
}
zstrdup()
char *zstrdup(const char *s) {
//获取源字符串长度,strlen()不统计'\0',故+1
size_t l = strlen(s)+1;
//调用zmalloc分配空间
char *p = zmalloc(l);
//void *memcpy(void *dest, const void *src, size_t n);
memcpy(p,s,l);
return p;
}