在编码过程中,我们往往只关心如何使用系统提供的API,比较容易忽略内在的原理。C/C++编码中,能够安全地管理内存是一项基础考察点。比如
- malloc和free一定要配对使用,否则导致内存泄漏
- 不要free内存两次
- 指针非空判断
- 不要跨模块malloc和free内存
- 野指针问题
而今天就来说说glibc内存malloc和free的源码探究以及说明下为什么free指针时,不需要指定内存块大小。
我是在这个网站找到了malloc和free的源码实现,这里给出其链接,附录给下查找过程。
https://code.woboq.org/userspace/glibc/malloc/malloc.c.html
基础定义
这里主要定义了一个allocation_header结构数组,大小为65536,结构体为记录要分配的实际内存大小和索引。
代码如下:
/* Array of known allocations, to track invalid frees. */
enum { max_allocations = 65536 };
/*全局数组变量,最大内存分配个数为65536*/
static struct allocation_header *allocations[max_allocations];
/*记录索引*/
static size_t allocation_index;
static size_t deallocation_count;
struct allocation_header
{
size_t allocation_index; /*分配索引*/
size_t allocation_size; /*分配大小*/
};
malloc实现
malloc函数内部调用了malloc_internal(), 从实现上看,malloc支持线程安全。
malloc_internal 记录了当前内存分配信息,包括实际内存分配大小和索引记录。实际内存分配会比用户申请的要多一个sizeof(allocation_header)
大小.
malloc_internal 代码如下:
static void *
malloc_internal (size_t size)
{
if (allocation_index == max_allocations)
{
errno = ENOMEM;
return NULL;
}
size_t allocation_size = size + sizeof (struct allocation_header);
if (allocation_size < size)
{
errno = ENOMEM;
return NULL;
}
size_t index = allocation_index++;
//实际内存分配
void *result = mmap (NULL, allocation_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (result == MAP_FAILED)
return NULL;
allocations[index] = result;
*allocations[index] = (struct allocation_header)
{
.allocation_index = index,
.allocation_size = allocation_size
};
//给用户分配的内存块开始地址,跳过头部地址
return allocations[index] + 1;
}
free实现
我们调用完malloc之后,我们都需要调用free接口才可以,但是我们只需要传入malloc返回的地址即可,大小信息可以从头部信息获取。
free源码如下:
void
free (void *ptr)
{
if (ptr == NULL)
return;
lock ();
//返回内存分配的头部信息,包含了分配的内存大小信息
//在get_header中对ptr-1,得到实际的内存分配地址。
struct allocation_header *header = get_header ("free", ptr);
//完成内存释放工作
free_internal ("free", header);
unlock ();
}
get_header 关键代码:
free_internal 内部实现:
申请内存块实际分配模型
以上就是全部glibc简单的内存管理源码分析,每个版本、编译器的内存管理会有差异,但最基本的原理应该都是这样了,欢迎大家指正~~~~
附录:
给出如何查找free源码实现过程
- 鼠标放在free关键字上
- 在definitions上选择tst-interpose-aux.c文件
3. 跳转完成后,找到free实现源码
4. 按照相同方法可以找到全部函数实现,和IDE一样可以实现函数跳转。