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;
 }


2.free

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

posted @ 2014-09-10 18:17  徐小鱼  阅读(482)  评论(0编辑  收藏  举报