malloc和free解析
malloc和free都是库函数,调用系统函数sbrk()来分配内存。除了分配可使用的内存以外,还分配了”控制“信息,这有点像内存池常用的手段。并且,分配的内存是连续的。
1. malloc
#include void malloc_init() { last_valid_address = sbrk(0);//从操作系统分配内存 managed_memory_start = last_valid_address;//设置全局变量 has_initialized = 1;//全局变量,标示已经被初始化 }
上面那个函数,从名字中就可以理解,是一个初始化函数。什么时候来初始化呢?我想应该是在自己的程序里第一次调用这个函数时会调用到malloc_init()。如果存在多次调用,则会走下面这个函数:
这个是分配内存的控制块:
struct mem_control_block { int is_available;//为0或1,等于1时表示可以重复使用 int size;//内存块的大小,包括本结构体在内 };
//清单 6. 主分配程序 void *malloc(long numbytes) { void *current_location;//无类型指针,表示“当前块”,后面可以知道,它相关于链表访问时,操作当前节点的指针 struct mem_control_block *current_location_mcb;//“当前块”的mem_control_block指针 void *memory_location;//真正会返回的地址指针,即malloc()返回的 if(! has_initialized) {//如果没有初始化,则调用该函数,第一次肯定没有初始化,故,该函数应该会在第一次调用malloc()时使用 malloc_init(); } numbytes = numbytes + sizeof(struct mem_control_block);//调整传进来的大小,包括mem_control_block这个结构体大小 memory_location = 0;//设置为0 current_location = managed_memory_start;//managed_memory_start为全局变量,保存一块连续内存的起始位置。它第一次在malloc_init()中设置 while(current_location != last_valid_address)//这里开始“遍历”,从managed_memory_start直到last_valid_address { current_location_mcb =(struct mem_control_block *)current_location;//无类型指针转换为mem_control_block指针 if(current_location_mcb->is_available)//如果当前块可用。这里is_available为1表示可用 { if(current_location_mcb->size >= numbytes)//如果当前块的大小足够使用的 { current_location_mcb->is_available = 0;//标示当前块已经被“占用”了 break;//跳出while表示找到了可用的块,其实是为了节约内存空间 } } current_location = current_location +current_location_mcb->size;//走到这里表示“当前块”不可用,current_location往后走“一块”的大小。 } //没有找到,则开辟新的内存 if(! memory_location) { sbrk(numbytes);//调用系统函数,分配内存 memory_location = last_valid_address;//这里的memory_location等于last_valid_address,我觉得应该是sbrk()这个系统调用所分配的新的块是与当前块连续的,同时,last_valid_address指向的是所有可用内存的“最后的边界” last_valid_address = last_valid_address + numbytes;//更新这个“边界” current_location_mcb = memory_location;//设置指针和结构体的值 current_location_mcb->is_available = 0; current_location_mcb->size = numbytes; } memory_location = memory_location + sizeof(struct mem_control_block);//指针“跳过”结构体大小,指向真正的可用内存,也就是malloc返回的指针 return memory_location; }
void free(void *firstbyte) { struct mem_control_block *mcb; mcb = firstbyte - sizeof(struct mem_control_block);//指针后退,退过mem_control_block的大小 mcb->is_available = 1;//标示该“块”可用 return; }free函数很简单,就是将当前可用指针后退到真正的“块”的起始位置,再设置“块”为可用(is_available=1),可见free也并不是把内存真正的释放掉了,只是作为标记。为什么要这样设置?从代码中可用看到,这样设置完之后,如果下次再调用malloc,将对所有的块进行搜索,找到这样一个可用的。这样的好处是什么?节约内存!相当于内存池里的重复利用。
参考资料:http://lklkdawei.blog.163.com/blog/static/32574109200881445518891/
http://blog.csdn.net/eroswang/article/details/4265024