阅读调试下面代码,将使你明白malloc 的工作原理
/*
整理: hjjdebug
time: 2009/4
该函数演示了malloc 的工作原理:
1. malloc 在一块平坦的内存区管理内存(可以称之为堆)
2. malloc 由管理块和数据块构成
3. malloc 首先以链表的方式搜索已管理的内存,没有找到,再从大池里扩展一块进入valid_address 管理区
*/
#include <stdio.h>
#include <stdlib.h>
//#include <conio.h>
#define SIZE 0x10000
struct mem_control_block
{
int is_available;
int size;
};
int has_initialized = 0;
void *g_managed_memory_start;
void *g_next_avail_address;
void malloc_init();
void myfree(void *firstbyte);
void *mymalloc(long numbytes);
void sbrk(int n)
{
// 它的愿意是内存不够了,从平坦内存中申请追加内存,但申请追加边界不能超过平坦内存边界
// 另外,若是真实的系统分配,此处是将零散的小内存合并为平坦的大内存的好位置。这里模拟就不用考虑了。
// 它的原意是返回g_next_avail_address
if(((long)g_next_avail_address+n)>(long)g_managed_memory_start+SIZE)
{
printf("memory full!/n");
exit(1);
}
}
// 测试程序
int main(void)
{
void *p1, *p2, *p3,*p4,*p5;
p1=mymalloc(0x100);
p2=mymalloc(0x200);
p3=mymalloc(0x300);
printf("p1 offset: %lx\n",(char *)p1-(char *)g_managed_memory_start);
printf("p2 offset: %lx\n",(char *)p2-(char *)g_managed_memory_start);
printf("p3 offset: %lx\n",(char *)p3-(char *)g_managed_memory_start);
myfree(p2);
p4=mymalloc(0x50);
p5=mymalloc(0x50);
printf("p4 offset: %lx\n",(char *)p4-(char *)g_managed_memory_start);
printf("p5 offset: %lx\n",(char *)p5-(char *)g_managed_memory_start);
myfree(p1);
myfree(p3);
myfree(p4);
myfree(p5);
// system("pause");
return 0;
}
// 仅执行一次, 模拟分配一块大内存,并为g_next_avail_address 付初值
void malloc_init()
{
/* grab the last valid address from the OS */
// g_managed_memory_start = sbrk(0);
g_managed_memory_start=malloc(SIZE);
/*just set the beginning to be g_next_avail_address
*/
g_next_avail_address = g_managed_memory_start;
/* Okay, we're initialized and ready to go */
has_initialized = 1;
}
// 将mcb 的标志置位即可
void myfree(void *firstbyte)
{
/* Backup from the given pointer to find the
* mem_control_block
*/
struct mem_control_block * mcb = (struct mem_control_block*)((long)firstbyte - sizeof(struct mem_control_block));
/* Mark the block as being available */
mcb->is_available = 1;
/* That's It! We're done. */
return;
}
/*
1. 首先进行一次初始化
2. 搜索已分配的内存块,看是否有空闲的,可满足要求的内存块。若有,结束
3. 若没有,从空白内存中追加一块。
*/
void *mymalloc(long numbytes)
{
/* Initialize if we haven't already done so */
if(! has_initialized) {
malloc_init();
}
/* The memory we search for has to include the memory
* control block, but the users of malloc don't need
* to know this, so we'll just add it in for them.
*/
numbytes = numbytes + sizeof(struct mem_control_block);
/* This is the memory location we will return. It will
* be set to 0 until we find something suitable
*/
void *memory_location = 0;
/* Holds where we are looking in memory
Begin searching at the start of managed memory */
void *current_location = g_managed_memory_start;//the start is fixed
/* Keep going until we have searched all allocated space */
while(current_location != g_next_avail_address)
{
/* current_location and mcb point
* to the same address. However, mcb
* is of the correct type, so we can use it as a struct.
* current_location is a void pointer so we can use it
* to calculate addresses.
*/
struct mem_control_block *mcb = (struct mem_control_block *)current_location;
if(mcb->is_available)
{
if(mcb->size >= numbytes)
{
/* Woohoo! We've found an open,
* appropriately-size location.
*/
/* It is no longer available */
mcb->is_available = 0;
/* We own it */
memory_location = current_location;
/* Leave the loop */
break;
}
}
/* If we made it here, it's because the Current memory
* block not suitable; move to the next one
*/
current_location = (char *)current_location + mcb->size;//look through the chain
}
/* If we still don't have a valid location, we'll
* have to ask the operating system for more memory
*/
if(!memory_location)
{
/* Move the program break numbytes further */
sbrk(numbytes);
/* The new memory will be where the last valid
* address left off
*/
memory_location = g_next_avail_address;
/* We need to initialize the mem_control_block */
mem_control_block *mcb = (mem_control_block *)memory_location;
mcb->is_available = 0;
mcb->size = numbytes;
/* We'll move the last valid address forward
* numbytes
*/
g_next_avail_address = (char *)g_next_avail_address + numbytes; //adjust g_next_avail_address
}
/* Now, no matter what (well, except for error conditions),
* memory_location has the address of the memory, including
* the mem_control_block
*/
/* Move the pointer past the mem_control_block */
memory_location = (char *)memory_location + sizeof(struct mem_control_block);
/* Return the pointer */
return memory_location;
}