+ -
当前位置:首页 → 问答吧 → 动态内存管理代码,求评价

动态内存管理代码,求评价

时间:2010-08-29

来源:互联网

由于嵌入式平台需求,自己写了个内存管理程序,可以动态分配和回收内存,求各位看官对该算法的评价。
C/C++ code

#include "stdio.h"
unsigned int free_tmp[1024*1024*2/4]={0};

//申请空间头结构
struct new_head{             
    unsigned int new_size; //申请空间块总大小
    unsigned int magic;    //合法性校验,值为(~new_size)
};

//空闲空间头结构
struct free_head{
    unsigned int free_size;   //空闲块总大小
    struct free_head * next;  //下一个空闲块指针
    unsigned int magic;       //合法性校验,值为 (next+~free_size)
};

struct free_head *global_first_pFreeHead;  //全局 地址最低的空闲块

//初始化动态内存块
int free_init(void* start_add,unsigned int size)
{
    global_first_pFreeHead = (struct free_head *)start_add;
    global_first_pFreeHead->next=NULL;
    global_first_pFreeHead->free_size=size;
    global_first_pFreeHead->magic=(unsigned int)global_first_pFreeHead->next+~global_first_pFreeHead->free_size;
    return 0;
}

//申请内存
void * new_n(unsigned int new_size)
{
    struct free_head * p_free=NULL;  //链表遍历指针
    struct free_head * tmp=NULL;     //暂存指针
    struct new_head * new_tmp;       //申请内存头指针

    new_size=(((new_size-1)>>2)<<2)+4; //使申请字节数为4的倍数

    for(p_free=global_first_pFreeHead;p_free!=NULL;p_free=p_free->next)  //查找空闲块链表中符合要求的最小块
    {
        /// for debug
        if(p_free->magic!=(unsigned int)p_free->next+~p_free->free_size) //检查空闲内存头合法性
        {
            printf("堆栈检查错误!堆栈被破坏!\r\n");
            return NULL;
        }

        if(p_free->free_size>=(new_size+sizeof(struct new_head)))
        {
            if(tmp==NULL || tmp->free_size>p_free->free_size)
            {
                tmp = p_free;
            }
        }
    }
    if(tmp!=NULL)   //从该空闲块中剥离申请空间
    {
        struct free_head * store_tmp;
        p_free=tmp;
        store_tmp=p_free;

        p_free=(struct free_head *)(((char *)p_free)+new_size+sizeof(struct new_head));
        p_free->free_size=store_tmp->free_size-(new_size+sizeof(struct new_head));
        p_free->next=store_tmp->next;
        p_free->magic=(unsigned int)p_free->next+~p_free->free_size;

        if(store_tmp==global_first_pFreeHead)
        {
            global_first_pFreeHead=p_free;
        }
    }
    else
        return NULL;
    
    // 将剥离的空间初始化,并返回可用空间指针
    new_tmp=(struct new_head *)tmp;
    new_tmp->new_size=new_size+sizeof(struct new_head);
    new_tmp->magic=~(new_tmp->new_size);
    return ((char *)new_tmp)+sizeof(struct new_head);
}

//释放空间
void free_n(void *p)
{
    struct new_head * p_tmp;    //
    struct free_head * p_new;   //
    struct free_head * p_free;  //链表遍历指针
    unsigned int bytes_num;     //记录释放空间大小

    p_tmp=(struct new_head *)((char *)p - sizeof(struct new_head)); //指向申请内存头
    if(p_tmp->new_size!=~p_tmp->magic) //检查内存头合法性
    {
        printf("wrong pointer to be free is detected! free failed!");
        return;
    }

    bytes_num=p_tmp->new_size;//记录释放空间大小
    p_new=(struct free_head *)p_tmp;  //将该内存块变为空闲块
    p_new->free_size=bytes_num;

    for(p_free=global_first_pFreeHead;;) //将释放区域插入链表中
    {
        /// for debug
        if(p_free->magic!=(unsigned int)p_free->next+~p_free->free_size) //检查空闲内存头合法性
        {
            printf("堆栈检查错误!堆栈被破坏!\r\n");
            return;
        }

        if(p_free==global_first_pFreeHead && p_free>p_new) //插入链表首位置
        {
            global_first_pFreeHead=p_new;
            p_new->next=p_free;
            break;
        }
        
        if(p_free < p_new && p_free->next > p_new)  //插入链表中间位置
        {
            p_new->next=p_free->next;
            
            p_free->next=p_new;
            p_free->magic=(unsigned int)p_free->next+~p_free->free_size;
            break;
        }
        
        if(p_free->next==NULL) //插入链表末尾
        {
            p_free->next=p_new;
            p_free->magic=(unsigned int)p_free->next+~p_free->free_size;
            
            p_new->next=NULL;
            break;
        }
        else
        {
            p_free=p_free->next;
        }
    }
    p_new->magic=(unsigned int)p_new->next+~p_new->free_size;

    for(p_free=global_first_pFreeHead;p_free!=NULL;p_free=p_free->next) //组合连续链表
    {
        int flag1,flag2=NULL;
        do
        {
            flag1=NULL;
            if(p_free == (struct free_head *)((char *)p_free->next - p_free->free_size))  //判断连续性
            {
                p_free->free_size = p_free->free_size + p_free->next->free_size;//必须先设置大小,然后再设置链表指针
                p_free->next = p_free->next->next;
                
                flag1=!NULL;
                flag2=!NULL;
            }
        }while(flag1);
        
        if(flag2) 
            p_free->magic=(unsigned int)p_free->next+~p_free->free_size;
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    unsigned int i=0;
    printf("%d  %u",sizeof(int),i-1);
    free_init(free_tmp,1024*1024*2);
    
    int * p0=(int *)new_n(sizeof(int));
    *p0=0x12345678;
    //free_n(p0);

    int *p1=(int *)new_n(sizeof(int));
    *p1=0x77777777;
    //free_n(p0);

    int *p2=(int *)new_n(sizeof(int)*1);
    p2[0]=0x12341234;
    //p2[1]=0x66668888;

    int * p3=(int *)new_n(sizeof(int)*1);
    p3[0]=0x11111111;
    //p3[1]=0x22222222;
    //p3[2]=0x33333333;

    free_n(p0);
    free_n(p2);
    free_n(p3);
    free_n(p1);
    return 0;
}


作者: bluehousedahui   发布时间: 2010-08-29

好长……不知道今年内我能不能看懂

作者: chuifeng56   发布时间: 2010-08-29

如果能够支持内存泄漏的检测就更好了。

作者: lazy_2010   发布时间: 2010-08-29

引用 2 楼 lazy_2010 的回复:

如果能够支持内存泄漏的检测就更好了。

这个可以实现,在写一个遍历空闲内存链表的程序,如果程序程序结束时检查一下是否为一个整体的内存块就可以了。

作者: bluehousedahui   发布时间: 2010-08-29

学习。。。。。。

作者: wing_0706   发布时间: 2010-08-29

方便调试,是指内存泄漏的时候可以知道文件、分配行;仅仅知道存在内存泄漏是不方便分析的;

另外,printf 这样的语句不知道在你的嵌入式系统中不知道是否可以,建议写一个 log 函数,在 log 函数中调用 printf,以后方面统一换成别的输出函数;

作者: lazy_2010   发布时间: 2010-08-30

算法上有问题。
主要在回收内存时,每一次都要全部遍历,这在效率上是无法接受的。
算法要考虑到“相邻块”就可以了。

作者: sinservice   发布时间: 2010-08-30

unsigned int free_tmp[1024*1024*2/4]={0};


不能动态预分配?如果起不到内存池的作用,那在应用层封装一层这样的api有什么意义?

此外,可以考虑加上检测重复free,以及内存越界的检测。

作者: hairetz   发布时间: 2010-08-30

看不太懂
纯顶

作者: cloudhsu   发布时间: 2010-08-30

引用 7 楼 hairetz 的回复:

unsigned int free_tmp[1024*1024*2/4]={0};


不能动态预分配?如果起不到内存池的作用,那在应用层封装一层这样的api有什么意义?

此外,可以考虑加上检测重复free,以及内存越界的检测。

那个数组纯粹是用VC模拟时构造出来的存储空间,在嵌入式里可以直接给出内存地址,不用那个数组了。

作者: bluehousedahui   发布时间: 2010-08-30