分享

(原创)模拟内存动态管理——学习篇

 happy123god 2012-03-26
                                                                  模拟内存动态管理——学习篇(原创)
 
本文简单讲讲操作系统对动态内存的管理策略,纯属个人粗浅认识,如果有错,还望指出。
如果转载,还请注明文章出处,谢谢!!
 
动态内存,即我们通过malloc/alloc等接口向操作系统申请到的内存。那操作系统是
如何管理的呢?

操作系统将空闲内存块以“链表”的方式维护起来。当我们调用malloc等接口向操作系统
申请内存时候,操作系统会在空闲内存链上查找是否有足够的可用内存。如果找到这样
的节点,则将此节点的内存块分成请求内存块和剩余内存块,将请求内存块返回给"malloc",
而将剩余内存块添加到空闲内存链上。
 
问题:在空闲内存链上搜索可用的内存块,操作系统会使用怎样的策略呢? 请参考
我转载的一篇讲述操作系统内存管理算法的文章,在这里,我只是就两个简单
的算法——best fit & first fit 进行初步的分析下。
 
First Fit : 在free list里面搜索,当找到的block比请求的大的话,就分割这个block将剩余
的插入到free list中.我们可以看到,这样的话会使得前面的block越来越小,从而导致每次
搜索都会越来越远(假设每次都是请求这样大小的内存块)。

Best Fit : 每次在free list里面搜索,找到不小于请求大小的,最接近请求大小的
内存块。它是从生成的内存碎片来看,最好的一种策略,因为它会产生最小的碎片.
可是由于它会每次遍历所有block,所以它的效率比较低。当然,也可对free list
按照free node 的大小进行排序,但这样的话,也是比较耗时的。
 
下面的程序简单模拟了操作系统管理内存的best fit和first fit算法。

1. Best Fit 示例程序

#if 1

/*
  This is a program to simulate malloc/free function
  If we use "best fit " strategy when we alloc memory ,
  the efficiency will be low when we look for the most
  proper size of memory block and when we collect memory
  fragments (we need to traverse the memory free list
  2 times ,because the address order of nodes in the list
  is not in order) , But the possiblity to encounter
  memory fragment collection will be lower .
 
  If we use "first fit " strategy when we alloc memory ,
  the efficiency will be higher , while the usage of
  memory may be inefficient.
 
  Here is 1 program using "Best Fit " Strategy .
*/

#include <stdio.h>
#include <stdlib.h>

#define  HEAP_SIZE  320

char heap_mem[HEAP_SIZE];

struct mem_ctrl_blk
{
    int  node_size;
    struct mem_ctrl_blk * next;
};

struct mem_ctrl_blk * phead = NULL;
// phead :  stands for the head node of memory list
struct mem_ctrl_blk * pfree_list = NULL;

int mem_ctrl_blk_size = sizeof(struct mem_ctrl_blk);

int mem_has_inited = 0;

extern void print_free_list();

void mem_init()
{
    phead = (struct mem_ctrl_blk *)heap_mem;
    phead->node_size = 0;
    pfree_list = phead + 1;
    pfree_list->node_size = HEAP_SIZE - mem_ctrl_blk_size;
    pfree_list->next = NULL;
    phead->next = pfree_list;
    mem_has_inited = 1;
}

void list_insert(struct mem_ctrl_blk *pnode)
{
    struct mem_ctrl_blk *p = pfree_list;
    struct mem_ctrl_blk *plast = phead;
   
    while(p)
    {
        if(p->node_size > pnode->node_size)
        {
            if(p == pfree_list)
            {
                pfree_list = pnode;
            }
            pnode->next = p;
            plast->next = pnode;
  
            return;
        }
        plast = p;
        p = p->next;
 }
    plast->next = pnode;
    pnode->next = NULL;  // in fact ,now p == NULL
}

void mem_frag_collect()
{
    struct mem_ctrl_blk *p = pfree_list;
    struct mem_ctrl_blk *plast = phead;
    struct mem_ctrl_blk *q;
   
    printf(" enter mem_frag_collect \n");
    // if only 1 node , there is no memory fragment
    printf(" pfree_list = %p , phead = %p \n",
             pfree_list,phead);
    while(p)
    {
        q = p->next;
        printf(" q = %p, p = %p \n",q,p);
        if(q)
        {
            printf(" q->node_size = %d , p->node_size = %d \n",
                     q->node_size,p->node_size);
        }
      
        if ((char *)p + p->node_size == (char *)q)
        {
            printf(" p + p_size = q \n");
            p->node_size += q->node_size;
            p->next = q->next;
        }
        else
        {
            p = p->next;
        }
    }
    printf(" exit mem_frag_collect \n");
}

// we use select sort ;  sort by node size 
void  mem_node_sort_after_collect()
{
    struct mem_ctrl_blk *p,*plast;
    struct mem_ctrl_blk *q,*qlast,*qlast_prev;
    struct mem_ctrl_blk *pmax_node,*pmax_prev;
    struct mem_ctrl_blk *plist_end = NULL;
   
    printf(" enter mem_node_sort_after_collect \n");
   
    p = pfree_list;
    plast = phead;
   
    while(p->next != plist_end)
    {
        pmax_node = p;
        qlast = p;
        q = p->next;
        pmax_prev = plast;
        qlast_prev = plast;
        while(q != plist_end)
        {
            if(pmax_node->node_size < q->node_size)
            {
                pmax_node = q;
                pmax_prev = qlast;
            }
            qlast_prev = qlast;
            qlast = q;
            q = q->next;
        }
        // do node switch
        // the max node is close to the last node in
        // current list
       if(qlast == pmax_node->next)
       {
           pmax_node->next = qlast->next;
           qlast->next = pmax_node;
           pmax_prev->next = qlast;
       }
       else
       {
           pmax_prev->next = qlast;
           qlast->next = pmax_node->next;
           qlast_prev->next = pmax_node;
           pmax_node->next = plist_end;
           plist_end = pmax_node;
       }
 
       if(p == pmax_node)
       {
           pfree_list = p = qlast;        
       }
    }
    printf(" exit mem_node_sort_after_collect \n");
}

void mem_node_sort_by_address()
{
    struct mem_ctrl_blk *p,*plast;
    struct mem_ctrl_blk *q,*qlast,*qlast_prev;
    struct mem_ctrl_blk *pmax_node,*pmax_prev;
    struct mem_ctrl_blk *plist_end = NULL;
   
    printf(" enter mem_node_sort_by_address \n");
   
    p = pfree_list;
    plast = phead;
   
    while(p->next != plist_end)
    {
        pmax_node = p;
        qlast = p;
        q = p->next;
        pmax_prev = plast;
        qlast_prev = plast;
   
        while(q != plist_end)
        {
            if(pmax_node < q)
            {
                pmax_node = q;
                pmax_prev = qlast;
            }
            qlast_prev = qlast;
            qlast = q;
            q = q->next;
        }
        // do node switch
        if(qlast == pmax_node->next)
        {
            pmax_node->next = qlast->next;
            qlast->next = pmax_node;
            pmax_prev->next = qlast;
        }
        else
        {
            pmax_prev->next = qlast;
            qlast->next = pmax_node->next;
            qlast_prev->next = pmax_node;
            pmax_node->next = plist_end;
            plist_end = pmax_node;
        }
 
        if(p == pmax_node)
        {
            pfree_list = p = qlast;        
        }
    }
    printf(" exit mem_node_sort_by_address \n");
}
 

void *mem_alloc(int num_bytes)
{
    int alloc_blk_size = num_bytes + mem_ctrl_blk_size;
    struct mem_ctrl_blk *pcur,*pmem,*prev;
    if(!mem_has_inited)
    {
        mem_init();
    }
    printf(" mem_alloc %d bytes \n",num_bytes);
    printf(" alloc_blk_size = %d \n", alloc_blk_size);
   
    prev = phead;
    pcur = prev->next; // means pfree_list
   
    while(pcur)
    {
        if(pcur->node_size < alloc_blk_size)
        {
            prev = pcur;
            pcur = pcur->next;
        }
        else
        {
            if(pcur->node_size - alloc_blk_size <= mem_ctrl_blk_size)
            {
                // do not need to split the memory
                pmem = pcur;
                if(pfree_list == pcur)
                {
                    pfree_list = pcur->next;
                }
                prev ->next = pcur->next;
            }
            else
            {
                // need to split the memory
                pcur->node_size = pcur->node_size - alloc_blk_size;
                printf("remaining node size is %d \n",pcur->node_size);
                pmem =(struct mem_ctrl_blk *)((char *)pcur + pcur->node_size);

                pmem->node_size = alloc_blk_size;
                pmem->next = NULL;
                // insert the left memory node into
                // free memory list,firstly we need to
                // remove this node from free memory list
                prev->next = pcur->next;
                list_insert(pcur);
            }
 
            printf(" mem alloced ,mcb_address = %p\n",pmem);
            printf(" mem alloc success , address = %p \n",
                     (void *)(pmem+1));
            return (void *)(pmem+1); 
            // skip the memory control block
        }
    }
    printf("not enough memory found in free memory list \n");
    printf("we need to collect memory fragment and check \n");
    printf(" before sort by address : \n");
    print_free_list();
    mem_node_sort_by_address();
    printf(" after sort by address : \n");
    print_free_list();
    mem_frag_collect();
    printf(" after memory fragment collection : \n");
    print_free_list();
    mem_node_sort_after_collect();
    printf(" after select sort by block size : \n");
    print_free_list();
    printf(" after memory fragment collection & sort "
           " we try to alloc memory \n");
  
    prev = phead;
    pcur = prev->next; // means pfree_list
    while(pcur)
    {
        if(pcur->node_size < alloc_blk_size)
        {
            prev = pcur;
            pcur = pcur->next;
        }
        else
        {
            if(pcur->node_size - alloc_blk_size <= mem_ctrl_blk_size)
            {
                // do not need to split the memory
                pmem = pcur;
                if(pfree_list == pcur)
                {
                    pfree_list = pcur->next;
                }
                prev ->next = pcur->next;
            }
            else
            {
                // need to split the memory
                pcur->node_size = pcur->node_size - alloc_blk_size;
                pmem = pcur + pcur->node_size;
                pmem->node_size = alloc_blk_size;
                pmem->next = NULL;
                // insert the left memory node into
                // free memory list,firstly we need to
                // remove this node from free memory list
                prev->next = pcur->next;
                list_insert(pcur);
            }
            printf(" mem alloced ,mcb_address = %p\n",pmem);
            printf(" mem alloc success , address = %p \n",
                     (void *)(pmem+1));
            return (void *)(pmem+1); 
            // skip the memory control block
        }
    }
    printf(" Not enough memory , fail to alloc \n");
    printf(" exit mem_alloc \n");
    return NULL;
}

/* If the parameter we pass to "mem_free" is not the one
   we alloc memory , what will happen ? 
   ((struct mem_ctrl_blk *)p - 1) , will not point to
   the memory control block ?
  
   For example :
   p = (char *) malloc (sizeof(char) * 100);
  
   free(p+3);
*/

void mem_free(void *p)
{
    struct mem_ctrl_blk *pfree_mcb = ((struct mem_ctrl_blk *)p - 1);
   
    printf(" mem_free : data address = %p \n",p);
    printf(" mcb_address = %p \n",pfree_mcb);
       
    list_insert(pfree_mcb);
   
}

void print_free_list()
{
    struct mem_ctrl_blk *p = pfree_list;
   
    printf("enter print_free_list \n");
    while(p)
    {
  
        printf("address = %p \n",p);
        printf("block size = %d \n",p->node_size);
        p = p->next;
    }
}

struct tagpp
{
    int x;
    int y;
};
 

int main()
{
    struct tagpp *pt_tag;
    char *p1,*p2,*p3,*p4,*p5;
    p1=p2=p3=p4=p5=NULL;
    printf(" heap memory address = %p \n",heap_mem);
    printf(" memory control block size is %d \n",
             mem_ctrl_blk_size);
    mem_init();
   
    printf(" before alloc any memory \n");
    print_free_list();        

    pt_tag =(struct tagpp*)mem_alloc(sizeof(struct tagpp));
    if(!pt_tag)
    {
        printf(" fail to alloc memory \n");
        print_free_list();
        return 0;
    }

    pt_tag->x=1;
    pt_tag->y=2;
       
            
    printf("x = %d y = %d\n",pt_tag->x,pt_tag->y);   
   
 
    mem_free(pt_tag);  
    printf("after free tagpp \n");   
    print_free_list();
   
    p1 = (char *)mem_alloc(100);
    if(!p1)
    {
        printf("fail to alloc memory for p1\n");
    }
   
    p2 = (char *)mem_alloc(50);
    if(!p2)
    {
        printf("fail to alloc memory for p2\n");
    }
   
    p3 = (char *)mem_alloc(30);
    if(!p3)
    {
        printf("fail to alloc memory for p3\n");
    }
   
    p4 = (char *)mem_alloc(20);
    if(!p4)
    {
        printf("fail to alloc memory for p4\n");
    }
   
    p5 = (char *)mem_alloc(4);
    if(!p5)
    {
        printf("fail to alloc memory for p5\n");
    }
 
    print_free_list();
   
    if(p5)
    {
        mem_free(p5);
        printf("p5 free \n");
    }
   
    p5 = (char *)mem_alloc(200);
    if(!p5)
    {
        printf("fail to alloc memory for p5\n");
    }
   
    if(p1)
    {
        mem_free(p1);
        printf("p1 free \n");
    }
    if(p2)
    {
        mem_free(p2);
        printf("p2 free \n");
    }
   
    if(p3)
    {
        mem_free(p3);
        printf("p3 free \n");
    }
   
    if(p4)
    {
        mem_free(p4);
        printf("p4 free \n");
    }
   
    if(p5)
    {
        mem_free(p5);
        printf("p5 free \n");
    }
   
    print_free_list();
   
    p5 = (char *)mem_alloc(200);
    if(!p5)
    {
        printf("fail to alloc memory for p5\n");
    }
    if(p5)
    {
        mem_free(p5);
        print_free_list();
    }
   
    system("PAUSE");
    return 0;
}
#endif



DEVC++下的运行结果如下:

 heap memory address = 00405070
 memory control block size is 8
 before alloc any memory
 
enter print_free_list
address = 00405078
block size = 312
 
 mem_alloc 8 bytes
 alloc_blk_size = 16
remaining node size is 296
 mem alloced ,mcb_address = 004051A0
 mem alloc success , address = 004051A8
 
x = 1 y = 2
 mem_free : data address = 004051A8
 mcb_address = 004051A0
 
after free tagpp
 
enter print_free_list
address = 004051A0
block size = 16
address = 00405078
block size = 296
 
 mem_alloc 100 bytes
 alloc_blk_size = 108
remaining node size is 188
 mem alloced ,mcb_address = 00405134
 mem alloc success , address = 0040513C
 
 mem_alloc 50 bytes
 alloc_blk_size = 58
remaining node size is 130
 mem alloced ,mcb_address = 004050FA
 mem alloc success , address = 00405102
 
 mem_alloc 30 bytes
 alloc_blk_size = 38
remaining node size is 92
 mem alloced ,mcb_address = 004050D4
 mem alloc success , address = 004050DC
 
 mem_alloc 20 bytes
 alloc_blk_size = 28
remaining node size is 64
 mem alloced ,mcb_address = 004050B8
 mem alloc success , address = 004050C0
 
 mem_alloc 4 bytes
 alloc_blk_size = 12
 mem alloced ,mcb_address = 004051A0
 mem alloc success , address = 004051A8
 
enter print_free_list
address = 00405078
block size = 64
 
 mem_free : data address = 004051A8
 mcb_address = 004051A0
p5 free
 
 mem_alloc 200 bytes
 alloc_blk_size = 208
not enough memory found in free memory list
we need to collect memory fragment and check
 
 before sort by address :
 
enter print_free_list
address = 004051A0
block size = 16
address = 00405078
block size = 64
 
 enter mem_node_sort_by_address
 exit mem_node_sort_by_address
 
 after sort by address :
 
enter print_free_list
address = 00405078
block size = 64
address = 004051A0
block size = 16
 
 enter mem_frag_collect
 
 pfree_list = 00405078 , phead = 00405070
 q = 004051A0, p = 00405078
 q->node_size = 16 , p->node_size = 64
 q = 00000000, p = 004051A0
 exit mem_frag_collect
 
 after memory fragment collection :
enter print_free_list
address = 00405078
block size = 64
address = 004051A0
block size = 16
 
 enter mem_node_sort_after_collect
 exit mem_node_sort_after_collect
 after select sort by block size :
enter print_free_list
address = 004051A0
block size = 16
address = 00405078
block size = 64
 
 after memory fragment collection & sort  we try to alloc memory
 Not enough memory , fail to alloc
 exit mem_alloc
 
fail to alloc memory for p5
 
 mem_free : data address = 0040513C
 mcb_address = 00405134
p1 free
 
 mem_free : data address = 00405102
 mcb_address = 004050FA
p2 free
 
 mem_free : data address = 004050DC
 mcb_address = 004050D4
p3 free
 
 mem_free : data address = 004050C0
 mcb_address = 004050B8
p4 free
 
enter print_free_list
address = 004051A0
block size = 16
address = 004050B8
block size = 28
address = 004050D4
block size = 38
address = 004050FA
block size = 58
address = 00405078
block size = 64
address = 00405134
block size = 108
 
 mem_alloc 200 bytes
 alloc_blk_size = 208
not enough memory found in free memory list
we need to collect memory fragment and check
 
 before sort by address :
 
enter print_free_list
address = 004051A0
block size = 16
address = 004050B8
block size = 28
address = 004050D4
block size = 38
address = 004050FA
block size = 58
address = 00405078
block size = 64
address = 00405134
block size = 108
 
 enter mem_node_sort_by_address
 exit mem_node_sort_by_address
 
 after sort by address :
 
enter print_free_list
address = 00405078
block size = 64
address = 004050B8
block size = 28
address = 004050D4
block size = 38
address = 004050FA
block size = 58
address = 00405134
block size = 108
address = 004051A0
block size = 16
 
 enter mem_frag_collect
 pfree_list = 00405078 , phead = 00405070
 
 q = 004050B8, p = 00405078
 q->node_size = 28 , p->node_size = 64
 p + p_size = q
 
 q = 004050D4, p = 00405078
 q->node_size = 38 , p->node_size = 92
 p + p_size = q
 
 q = 004050FA, p = 00405078
 q->node_size = 58 , p->node_size = 130
 p + p_size = q
 
 q = 00405134, p = 00405078
 q->node_size = 108 , p->node_size = 188
 p + p_size = q
 
 q = 004051A0, p = 00405078
 q->node_size = 16 , p->node_size = 296
 p + p_size = q
 
 q = 00000000, p = 00405078
 exit mem_frag_collect
 
 after memory fragment collection :
 
enter print_free_list
address = 00405078
block size = 312
 
 enter mem_node_sort_after_collect
 exit mem_node_sort_after_collect
 after select sort by block size :
 
enter print_free_list
address = 00405078
block size = 312
 after memory fragment collection & sort  we try to alloc memory
 mem alloced ,mcb_address = 004053B8
 mem alloc success , address = 004053C0
 mem_free : data address = 004053C0
 mcb_address = 004053B8
 
enter print_free_list
address = 00405078
block size = 104
address = 004053B8
block size = 208
请按任意键继续. . .


小结 : 
在malloc的时候,我们会从内存链上找第一个符合大小要求的内存块,是因为我们在调用
free释放内存的时候,会将释放的内存块插入到空闲内存链的合适位置,使得此链表依然
是按内存块大小升序排列的,当然,其实在调用free释放内存时不应该做那么多事情;但
如果此时不做内存块插入的动作,那么就要在每次调用malloc的时候,进行内存块按大小
升序排列的动作,而对应的排序的时间复杂度为O(n2),比起在free的时候进行插入排序
的时间复杂度O(n),时间上实在太耗时了。

之所以要进行sort by address,是因为我们要进行memory collect,如果不排序,对链表
里面的节点按照地址进行merge,时间复杂度高,并且容易出错。

当在空闲内存链上找不到请求大小的内存块的时候,我们就要进行memory collect了,
然后再从链表上搜索是否有合适大小的内存块,如果有,则申请成功,否则申请失败。
当然,我们可以看到,进行memory collect是非常耗时的,需要排序,针对上面的
best fit策略,我们需要排序两次 ( sort by node address  & sort by node size )。


 
==============================================================
2.First Fit示例程序
 
#if 1

/*
  Here is 1 program using "First Fit " Strategy .
*/

#include <stdio.h>
#include <stdlib.h>

#define  HEAP_SIZE  320

char heap_mem[HEAP_SIZE];

struct mem_ctrl_blk
{
    int  node_size;
    struct mem_ctrl_blk * next;
};

struct mem_ctrl_blk * phead = NULL;
// phead :  stands for the head node of memory list
struct mem_ctrl_blk * pfree_list = NULL;

int mem_ctrl_blk_size = sizeof(struct mem_ctrl_blk);

int mem_has_inited = 0;

extern void print_free_list();

void mem_init()
{
    phead = (struct mem_ctrl_blk *)heap_mem;
    phead->node_size = 0;
    pfree_list = phead + 1;
    pfree_list->node_size = HEAP_SIZE - mem_ctrl_blk_size;
    pfree_list->next = NULL;
    phead->next = pfree_list;
    mem_has_inited = 1;
}

void list_insert(struct mem_ctrl_blk *pnode)
{  
    pnode->next = phead->next;
    phead->next = pnode;
    pfree_list = pnode;
}

void mem_frag_collect()
{
    struct mem_ctrl_blk *p = pfree_list;
    struct mem_ctrl_blk *plast = phead;
    struct mem_ctrl_blk *q;
   
    printf(" enter mem_frag_collect \n");
    // if only 1 node , there is no memory fragment
    printf(" pfree_list = %p , phead = %p \n",
             pfree_list,phead);
    while(p)
    {
        q = p->next;
        printf(" q = %p, p = %p \n",q,p);
        if(q)
        {
            printf(" q->node_size = %d , p->node_size = %d \n",
                     q->node_size,p->node_size);
  }
      
        if ((char *)p + p->node_size == (char *)q)
        {
            printf(" p + p_size = q \n");
            p->node_size += q->node_size;
            p->next = q->next;
        }
        else
        {
            p = p->next;
        }
    }
    printf(" exit mem_frag_collect \n");
}

void mem_node_sort_by_address()
{
    struct mem_ctrl_blk *p_unsorted_list_head,*psorted_list_end;
    struct mem_ctrl_blk *pmin_addr,*pmin_addr_last;   
    struct mem_ctrl_blk *q,*qlast;
   
    printf(" enter mem_node_sort_by_address \n");
   
    pmin_addr = p_unsorted_list_head = pfree_list;
    psorted_list_end = phead;
   
    while(p_unsorted_list_head)
    {
        pmin_addr = p_unsorted_list_head;
        q = p_unsorted_list_head->next;
        qlast = pmin_addr;
       
        while(q)
        {  
            if(pmin_addr > q)
            {
                pmin_addr = q;
                pmin_addr_last = qlast;
            }
            qlast = q;
            q = q->next;
        }
        if(pmin_addr == p_unsorted_list_head)   // min address node is the unsorted head
        {
            p_unsorted_list_head = p_unsorted_list_head->next;
            pmin_addr->next = NULL;
            psorted_list_end->next = pmin_addr;
            psorted_list_end = pmin_addr;
        }
        else // min address node is not the unsorted head
        {
            pmin_addr_last->next =  pmin_addr->next;
            pmin_addr->next = NULL;
            psorted_list_end->next = pmin_addr;
            psorted_list_end = pmin_addr;
        }
    }   
   
    printf(" exit mem_node_sort_by_address \n");
}
 

void *mem_alloc(int num_bytes)
{
    int alloc_blk_size = num_bytes + mem_ctrl_blk_size;
    struct mem_ctrl_blk *pcur,*pmem,*prev;
    if(!mem_has_inited)
    {
        mem_init();
    }
    printf(" mem_alloc %d bytes \n",num_bytes);
    printf(" alloc_blk_size = %d \n", alloc_blk_size);
   
    prev = phead;
    pcur = prev->next; // means pfree_list
   
    while(pcur)
    {
        if(pcur->node_size < alloc_blk_size)
        {
            prev = pcur;
            pcur = pcur->next;
        }
        else
        {
            if(pcur->node_size - alloc_blk_size <= mem_ctrl_blk_size)
            {
                // do not need to split the memory
                pmem = pcur;
                if(pfree_list == pcur)
                {
                    pfree_list = pcur->next;
                }
                prev ->next = pcur->next;
            }
            else
            {
                // need to split the memory
                pcur->node_size = pcur->node_size - alloc_blk_size;
                printf("remaining node size is %d \n",pcur->node_size);
                pmem =(struct mem_ctrl_blk *)((char *)pcur + pcur->node_size);

                pmem->node_size = alloc_blk_size;
                pmem->next = NULL;
                // insert the left memory node into
                // free memory list,firstly we need to
                // remove this node from free memory list
                prev->next = pcur->next;
                list_insert(pcur);
            }
 
            printf(" mem alloced ,mcb_address = %p\n",pmem);
            printf(" mem alloc success , address = %p \n",
                     (void *)(pmem+1));
            return (void *)(pmem+1); 
            // skip the memory control block
        }
    }
    printf("not enough memory found in free memory list \n");
    printf("we need to collect memory fragment and check \n");
    printf(" before sort by address : \n");
    print_free_list();
    mem_node_sort_by_address();
    printf(" after sort by address : \n");
    print_free_list();
    mem_frag_collect();
    printf(" after memory fragment collection : \n");
    print_free_list();
    printf(" after memory fragment collection  "
           " we try to alloc memory \n");
  
    prev = phead;
    pcur = prev->next; // means pfree_list
    while(pcur)
    {
        if(pcur->node_size < alloc_blk_size)
        {
            prev = pcur;
            pcur = pcur->next;
        }
        else
        {
            if(pcur->node_size - alloc_blk_size <= mem_ctrl_blk_size)
            {
                // do not need to split the memory
                pmem = pcur;
                if(pfree_list == pcur)
                {
                    pfree_list = pcur->next;
                }
                prev ->next = pcur->next;
            }
            else
            {
                // need to split the memory
                pcur->node_size = pcur->node_size - alloc_blk_size;
                pmem = pcur + pcur->node_size;
                pmem->node_size = alloc_blk_size;
                pmem->next = NULL;
                // insert the left memory node into
                // free memory list,firstly we need to
                // remove this node from free memory list
                prev->next = pcur->next;
                list_insert(pcur);
            }
            printf(" mem alloced ,mcb_address = %p\n",pmem);
            printf(" mem alloc success , address = %p \n",
                     (void *)(pmem+1));
            return (void *)(pmem+1); 
            // skip the memory control block
        }
    }
    printf(" Not enough memory , fail to alloc \n");
    printf(" exit mem_alloc \n");
    return NULL;
}

/* If the parameter we pass to "mem_free" is not the one
   we alloc memory , what will happen ? 
   ((struct mem_ctrl_blk *)p - 1) , will not point to
   the memory control block ?
  
   For example :
   p = (char *) malloc (sizeof(char) * 100);
  
   free(p+3);
*/

void mem_free(void *p)
{
    struct mem_ctrl_blk *pfree_mcb = ((struct mem_ctrl_blk *)p - 1);
   
    printf(" mem_free : data address = %p \n",p);
    printf(" mcb_address = %p \n",pfree_mcb);
       
    list_insert(pfree_mcb);
   
}

void print_free_list()
{
    struct mem_ctrl_blk *p = pfree_list;
   
    printf("enter print_free_list \n");
    while(p)
    {
  
        printf("address = %p \n",p);
        printf("block size = %d \n",p->node_size);
        p = p->next;
    }
}

struct tagpp
{
    int x;
    int y;
};
 

int main()
{
    struct tagpp *pt_tag;
    char *p1,*p2,*p3,*p4,*p5;
    p1=p2=p3=p4=p5=NULL;
    printf(" heap memory address = %p \n",heap_mem);
    printf(" memory control block size is %d \n",
             mem_ctrl_blk_size);
    mem_init();
   
    printf(" before alloc any memory \n");
    print_free_list();        

    pt_tag =(struct tagpp*)mem_alloc(sizeof(struct tagpp));
    if(!pt_tag)
    {
        printf(" fail to alloc memory \n");
        print_free_list();
        return 0;
    }

    pt_tag->x=1;
    pt_tag->y=2;
       
            
    printf("x = %d y = %d\n",pt_tag->x,pt_tag->y);   
   
 
    mem_free(pt_tag);  
    printf("after free tagpp \n");   
    print_free_list();
   
    p1 = (char *)mem_alloc(100);
    if(!p1)
    {
        printf("fail to alloc memory for p1\n");
    }
   
    p2 = (char *)mem_alloc(50);
    if(!p2)
    {
        printf("fail to alloc memory for p2\n");
    }
   
    p3 = (char *)mem_alloc(30);
    if(!p3)
    {
        printf("fail to alloc memory for p3\n");
    }
   
    p4 = (char *)mem_alloc(20);
    if(!p4)
    {
        printf("fail to alloc memory for p4\n");
    }
   
    p5 = (char *)mem_alloc(4);
    if(!p5)
    {
        printf("fail to alloc memory for p5\n");
    }
 
    print_free_list();
   
    if(p5)
    {
        mem_free(p5);
        printf("p5 free \n");
    }
   
    p5 = (char *)mem_alloc(200);
    if(!p5)
    {
        printf("fail to alloc memory for p5\n");
    }
   
    if(p1)
    {
        mem_free(p1);
        printf("p1 free \n");
    }
    if(p5)
    {
        mem_free(p5);
        printf("p5 free \n");
    }
    if(p3)
    {
        mem_free(p3);
        printf("p3 free \n");
    }
   
    if(p2)
    {
        mem_free(p2);
        printf("p2 free \n");
    }
   
   
    if(p4)
    {
        mem_free(p4);
        printf("p4 free \n");
    }
   
   
    print_free_list();
   
    p5 = (char *)mem_alloc(200);
    if(!p5)
    {
        printf("fail to alloc memory for p5\n");
    }
    if(p5)
    {
        mem_free(p5);
        print_free_list();
    }
   
    system("PAUSE");
    return 0;
}
#endif
 
VC++6.0下的运行结果为:
 
  heap memory address = 0042AC78
 memory control block size is 8

 before alloc any memory
enter print_free_list
address = 0042AC80
block size = 312

 mem_alloc 8 bytes
 alloc_blk_size = 16
remaining node size is 296
 mem alloced ,mcb_address = 0042ADA8
 mem alloc success , address = 0042ADB0

x = 1 y = 2

 mem_free : data address = 0042ADB0
 mcb_address = 0042ADA8

after free tagpp
enter print_free_list
address = 0042ADA8
block size = 16
address = 0042AC80
block size = 296

 mem_alloc 100 bytes
 alloc_blk_size = 108
remaining node size is 188
 mem alloced ,mcb_address = 0042AD3C
 mem alloc success , address = 0042AD44

 mem_alloc 50 bytes
 alloc_blk_size = 58
remaining node size is 130
 mem alloced ,mcb_address = 0042AD02
 mem alloc success , address = 0042AD0A

 mem_alloc 30 bytes
 alloc_blk_size = 38
remaining node size is 92
 mem alloced ,mcb_address = 0042ACDC
 mem alloc success , address = 0042ACE4

 mem_alloc 20 bytes
 alloc_blk_size = 28
remaining node size is 64
 mem alloced ,mcb_address = 0042ACC0
 mem alloc success , address = 0042ACC8

 mem_alloc 4 bytes
 alloc_blk_size = 12
remaining node size is 52
 mem alloced ,mcb_address = 0042ACB4
 mem alloc success , address = 0042ACBC

enter print_free_list
address = 0042AC80
block size = 52
address = 0042ADA8
block size = 16

 mem_free : data address = 0042ACBC
 mcb_address = 0042ACB4
p5 free

 mem_alloc 200 bytes
 alloc_blk_size = 208
not enough memory found in free memory list
we need to collect memory fragment and check

 before sort by address :
enter print_free_list
address = 0042ACB4
block size = 12
address = 0042AC80
block size = 52
address = 0042ADA8
block size = 16

 enter mem_node_sort_by_address
 exit mem_node_sort_by_address

 after sort by address :
enter print_free_list
address = 0042AC80
block size = 52
address = 0042ACB4
block size = 12
address = 0042ADA8
block size = 16

 enter mem_frag_collect
 pfree_list = 0042AC80 , phead = 0042AC78
 q = 0042ACB4, p = 0042AC80
 q->node_size = 12 , p->node_size = 52
 p + p_size = q
 q = 0042ADA8, p = 0042AC80
 q->node_size = 16 , p->node_size = 64
 q = 00000000, p = 0042ADA8
 exit mem_frag_collect

 after memory fragment collection :
enter print_free_list
address = 0042AC80
block size = 64
address = 0042ADA8
block size = 16

 after memory fragment collection   we try to alloc memory
 Not enough memory , fail to alloc
 exit mem_alloc

fail to alloc memory for p5
 mem_free : data address = 0042AD44
 mcb_address = 0042AD3C
p1 free

 mem_free : data address = 0042ACE4
 mcb_address = 0042ACDC
p3 free

 mem_free : data address = 0042AD0A
 mcb_address = 0042AD02
p2 free

 mem_free : data address = 0042ACC8
 mcb_address = 0042ACC0
p4 free

enter print_free_list
address = 0042ACC0
block size = 28
address = 0042AD02
block size = 58
address = 0042ACDC
block size = 38
address = 0042AD3C
block size = 108
address = 0042AC80
block size = 64
address = 0042ADA8
block size = 16
 mem_alloc 200 bytes
 alloc_blk_size = 208
not enough memory found in free memory list
we need to collect memory fragment and check

 before sort by address :
enter print_free_list
address = 0042ACC0
block size = 28
address = 0042AD02
block size = 58
address = 0042ACDC
block size = 38
address = 0042AD3C
block size = 108
address = 0042AC80
block size = 64
address = 0042ADA8
block size = 16

 enter mem_node_sort_by_address
 exit mem_node_sort_by_address

 after sort by address :
enter print_free_list
address = 0042AC80
block size = 64
address = 0042ACC0
block size = 28
address = 0042ACDC
block size = 38
address = 0042AD02
block size = 58
address = 0042AD3C
block size = 108
address = 0042ADA8
block size = 16

 enter mem_frag_collect
 pfree_list = 0042AC80 , phead = 0042AC78
 q = 0042ACC0, p = 0042AC80
 q->node_size = 28 , p->node_size = 64
 p + p_size = q
 q = 0042ACDC, p = 0042AC80
 q->node_size = 38 , p->node_size = 92
 p + p_size = q
 q = 0042AD02, p = 0042AC80
 q->node_size = 58 , p->node_size = 130
 p + p_size = q
 q = 0042AD3C, p = 0042AC80
 q->node_size = 108 , p->node_size = 188
 p + p_size = q
 q = 0042ADA8, p = 0042AC80
 q->node_size = 16 , p->node_size = 296
 p + p_size = q
 q = 00000000, p = 0042AC80
 exit mem_frag_collect

 after memory fragment collection :
enter print_free_list
address = 0042AC80
block size = 312

 after memory fragment collection   we try to alloc memory
 mem alloced ,mcb_address = 0042AFC0
 mem alloc success , address = 0042AFC8
 mem_free : data address = 0042AFC8
 mcb_address = 0042AFC0

enter print_free_list
address = 0042AFC0
block size = 208
address = 0042AC80
block size = 104
请按任意键继续. . .



小结 : 
在malloc的时候,我们会从内存链上找第一个符合大小要求的内存块,
当然,此例中调用free释放内存时做的事情很少;但由此带来的sort by address
效率较低。当然,sort by address只会出现在需要memory collect的地方。
也就是说,当系统中memory collect出现次数较少时,此例中的free函数“比较高效”,
但一旦内存碎片较多,而memory collect出现的次数也不少时,建议还是在free结点
的时候,进行插入排序 (O(n)的时间复杂度),而不要等到memory collect,去调用
sort by address时,进行O(n2)的排序。


之所以要进行sort by address,是因为我们要进行memory collect,如果不排序,
对链表里面的节点按照地址进行merge,时间复杂度高,并且容易出错。

当在空闲内存链上找不到请求大小的内存块的时候,我们就要进行memory collect了,
然后再从链表上搜索是否有合适大小的内存块,如果有,则申请成功,否则申请失败。

可以看到,进行memory collect是非常耗时的,需要排序,针对上面的first fit策略,
我们需要排序( sort by node address  )。



可改进的地方:  1.线程安全性  2. 函数效率 3.对申请的内存按大小(可以是8字节)进行对齐。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多