有关标准库首先简要malloc其原理:
标准库内部通过一个双向链表。管理在堆中动态分配的内存。
malloc函数分配内存时会附加若干(一般是12个)字节,存放控制信息。
该信息一旦被意外损坏,可能在兴许操作中引发异常。
malloc函数分配内存时会附加若干(一般是12个)字节,存放控制信息。
该信息一旦被意外损坏,可能在兴许操作中引发异常。
mmap/munmap 底层不维护不论什么东西,仅仅是返回一个首地址,所分配内存位于堆中。
brk/sbrk 底层维护一个指针,记录所分配的内存结尾,所分配内存位于堆中,底层调用mmap/munmap。
malloc 底层维护一个双向链表和必要的控制信息,不可越界訪问。所分配内存位于堆中,底层调用brk/sbrk。
每一个进程都有4G的虚拟内存空间。虚拟内存地址仅仅是一个数字,并没有和实际的物理内存相关联。
所谓内存分配与释放,其本质就是建立或取消虚拟内存和物理内存间的映射关系。
几个用到的函数:
void*
sbrk (
intptr_t increment // 内存增量(以字节为单位)
);
sbrk (
intptr_t increment // 内存增量(以字节为单位)
);
返回上次调用brk/sbrk后的末尾地址,失败返回-1。
increment取值:
0 - 获取末尾地址。
>0 - 添加内存空间。
<0 - 释放内存空间。
内部维护一个指针。指向当前堆内存最后一个字节的下一个位置。
0 - 获取末尾地址。
>0 - 添加内存空间。
<0 - 释放内存空间。
内部维护一个指针。指向当前堆内存最后一个字节的下一个位置。
sbrk函数依据增量參数调整该指针的位置,同一时候返回该指针原来的位置。
若发现页耗尽或空暇。则自己主动追加或取消页映射。
int
brk (
brk (
void* end_data_segment // 内存块末尾地址
);
成功返回0。失败返回-1。
);
成功返回0。失败返回-1。
内部维护一个指针,指向当前堆内存最后一个字节的下一个位置。
brk函数依据指针參数设置该指针的位置。
若发现页耗尽或空暇。则自己主动追加或取消页映射。
sbrk/brk底层维护一个指针位置,以页(4K)为单位分配和释放虚拟内存。
简便起见,可用sbrk分配内存。用brk释放内存。
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
typedef struct mem_control_block //内存控制块
{
bool free; //*标志
struct mem_control_block* prev; //前向指针
size_t size; //块大小
}MCB;
MCB* g_top; //内存栈顶指针 // +----------------------+ g_top
// v | |
// +------+------------+--|---+------------+------+------------+
// | prev | | prev | | prev | |
// | free | | free | | free | |
// | size | | size | | size | |
// +------+------------+------+------------+------+------------+
// MCB |<-- size -->| void* my_malloc(size_t size)
{
MCB* mcb;
for(mcb = g_top; mcb; mcb = mcb->prev)
if(mcb->free && mcb->size >= size)//寻找可用空块
break;
if(!mcb) //假设没有可用空块
{
mcb = sbrk(sizeof(MCB) + size); //增量分配size大小内存
if(mcb == (void*)-1) //假设分配失败,打印错误信息
{
perror("sbrk");
return NULL;
}
mcb->prev = g_top; //调整前向指针
mcb->size = size; //大小
g_top = mcb; //调整栈顶指针
}
mcb->free = false; //不管用原来空块还是新分配的块,都标记为不可用
return mcb + 1; //返回实际分配的内存起始地址
}
void my_free(void* ptr)
{
if(!ptr)
return; MCB* mcb = (MCB*)ptr - 1; //取控制块起始地址,
//注意:ptr为实际可用内存起始地址
mcb->free = true; //块标记为可用 //在栈中查找连续内存块
for(mcb = g_top; mcb->prev; mcb = mcb->prev)
if(!mcb->free)
break;
//释放整个栈全部内存块
if(mcb->free)
{
g_top = mcb->prev;
brk(mcb); //改动内存块末尾地址
}
else //释放连续的标记为true的内存块
{
g_top = mcb;
brk((void*)mcb + sizeof(MCB) + mcb->size);
}
}
//測试
int main(void)
{
int* pa[10];
size_t size = sizeof(pa) / sizeof(pa[0]), i, j;
for(i = 0; i < size; ++i)
{
if(!(pa[i] = (int*)my_malloc((i+1) * sizeof(int))))
{
perror("my_malloc");
return -1;
}
for(j = 0; j <= i; ++j)
pa[i][j] = j;
}
for(i = 0; i < size; ++i)
{
for(j = 0; j <= i; ++j)
printf("%d ", pa[i][j]);
printf("\n");
}
for(;;)
{
my_free(pa[--i]);
if(! i)
break;
}
return 0;
}
版权声明:本文博主原创文章,博客,未经同意不得转载。