动态内存管理

来源:互联网 发布:中国资讯型数据库作用 编辑:程序博客网 时间:2024/05/14 11:33

 动态内存管理
在很多嵌入式设备上没有操作系统,没有C库,即裸机环境,有一些PC的外接设备,自己本身带有ddr内存,需要主机的驱动程序来管理。现在模拟一个这样的环境,实现自己的malloc和free函数。这三个函数接口如下:     
   库函数的动态内存分配函数min_init,min_malloc和min_free
intmin_init(void **start , int length)
   功能:初始化我们自己内存管理器,并指定管理器需要管理的内存区域,初始化成功返回0,否则返回-    功能:返回一个指针指向size大小的内存,如果没有足够的内存空间,则返回NULL
void *min_malloc(int length)
   功能:如果指针p为空,则什么都不做,指针p指向的地址必须是min_malloc分配的地址,否则异常.
 
   针对上面的题目,首先要弄懂题目的意思
 
一、初始化内存管理器
    这里的内存指的是一段连续的内存,我们可以向系统申请一块连续的内存让我们管理。这段连续的内存可以这样的方式来申请:
my_mem_pool = (TypeData*)malloc(sizeof(TypeData)*length) ;
这样就可以得到我们要管理内存的首地址,且地址是连续的
 
   在动态管理的过程中,可能随时进行内存的分配与释放,因此我们要建立两个动态的链表来存储已经用的内存块和现在余下的内存块
 
*空闲内存链表*/  typedef struct free{ int mem_length ; TypeData *begin ; TypeData *end ; struct free *next ; struct free *uplink ; //上一个节点的地址 }FREE; /*已用内存链表*/  typedef struct used{ int mem_length ; TypeData *begin ; TypeData *end ; struct used *next ;}USED; </span>
这个链表可以是带头结点的也可以是不带头结点的,我在程序中建立的是带头结点的。

二、动态分配内存

在内存分配的过程中,首先要检查内存是否已满和有没有用户所需要大小的内存块。每分配一块内存,都要新建立一个free链表节点,然后获得这块块内存的信息(首地址、尾地址、长度、上一个内存块在链表中的地址),把该节点插入到free链表中去。
       在找符合条件的内存块的时候有三种原则:
最先匹配
最优匹配
最差匹配
最先匹配:在链栈中查找符合条件的内存块时,找到第一块长度大于所需要的长度size的内存,分配出size大小给用户。
      最优匹配:在空闲链表中找到一个不小于size并且最接近size的空闲块分配给用户。分配时需要遍历整个链表。如果链表按空闲块从小到大有序,分配时只需找到第一个大于size的空闲块,回收时需要插入到链表合适的位置上。
      最差匹配: 在空闲(free)链表上找到一个内存块大于size,并且都大于其他的内存块,分配出size大小给用户。

三、内存回收
在回收的过程中,首先要判断该地址是否是min_malloc()函数来分配出来的。回收时,要看一下能不能和free链表上的空闲块进行合并,如果能合并就要先合并,这样能最大程度的利用内存。

我简单的用C语言代码的实现了一下,里面的有些变量命名不是很规范,函数的实现可能也不是最简单的,希望能和大家多多交流。

/* 使用两条链表实现可变长度的内存分配和回收,可任意申请和分配;*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <math.h>typedef char TypeData ;#define MEM_POOL_LENGTH 200/*空闲内存链表*/  typedef struct free{ int mem_length ; TypeData *begin ; TypeData *end ; struct free *next ; struct free *uplink ; //上一个节点的地址 }FREE; /*已用内存链表*/  typedef struct used{ int mem_length ; TypeData *begin ; TypeData *end ; struct used *next ;}USED; /*------------------------------------------------------------------*//*空闲链表,带头结点*/FREE *head_free = NULL ;/*已经被用到的链表,带头结点*/USED *head_used = NULL ;/*---------------------------------------------------------------------*//*功能:初始化我们自己内存管理器,        并指定管理器需要管理的内存区域        返回值: 初始化成功返回0,        否则返回-1        */int min_init(TypeData **start, const unsigned long size){/*需要分配的内存为0*/if(0 == size){return -1 ;}/*分配size大小的空间*/TypeData *p = (TypeData*)malloc(sizeof(TypeData)*size) ;if(NULL == p){return -1 ;}(*start) = p ;printf("需要管理的内存块地址为:%p ~ %p\n\n",p,p+sizeof(TypeData)*size -1) ;/*带头结点的used链表,mem_length = 0 */ head_used = (USED*)malloc(sizeof(USED)) ;head_used->next = NULL ; head_used->mem_length = 0 ;/*带头结点的free链表,mem_length = 0 */ head_free = (FREE*)malloc(sizeof(FREE)) ;head_free->next = NULL ;head_free->mem_length = 0 ; /*把全部的内存空间先挂载到free链表上去*/ FREE *p_free = (FREE*)malloc(sizeof(FREE)) ;p_free->begin = (*start) ;p_free->end = ( (*start) + sizeof(TypeData)*(size -1) ) ;p_free->mem_length = size ;p_free->next = NULL ;/*uplink 指向该节点的前一个节点的地址*/p_free->uplink = head_free ;head_free->next = p_free ;return 0 ;}/* 功能: 返回一个指针指向size大小的内存 返回值:  如果没有足够的内存空间,则返回NULL 匹配原则:最优匹配     */ TypeData *min_malloc(const int  size){/**存放要返回地址的指针*/TypeData *return_temp = NULL ;/*暂存used链表的头结点*/USED *p_used = NULL ;/*该变量是申请used链表的临时节点*/ USED *p_temp_used = NULL ;/*该变量存储free链表的头*/FREE *temp = NULL ;/*该变量存储要分配给用户空间在链表上的节点*/ FREE *now_free = NULL ;/*该变量存储符合条件的空间与需要的空间的差值*/int distance = -1 , temp_dis = 0 ; ;/*如果申请的内存大小,大于内存池的长度*/if(size > MEM_POOL_LENGTH){return NULL ;}/*内存空间已经用完*/if(NULL == head_free->next){return NULL ;}/*该变量存储free链表的头*/temp = head_free->next ;while(NULL != temp) {/*找到一块符合条件的内存*/if(temp->mem_length >= size){/*第一块符合条件的内存,直接给distance*/if(-1 == distance){distance = temp->mem_length - size ; now_free = temp ;} else{temp_dis = temp->mem_length - size ;/*如果这一块内存大小更接近所需要的内存大小*/ if(temp_dis < distance){distance = temp_dis ; now_free = temp ; }}}//if(temp->mem_length >= siztemp = temp->next ;}//while(NULL != temp)/*没有找到符合条件的内存块*/if(-1 == distance){return NULL ; }/*这块内存大小和用户需求的不一样,大于用户需求,需要裁剪一块*/if(0 < distance){/*暂存要返回的地址*/ return_temp = now_free->begin ;/*把该内存块,挂载到used链表上去*/p_used = head_used ;/*找到末尾节点*/while(NULL != p_used->next ){p_used = p_used->next ;} p_temp_used = (USED*)malloc(sizeof(USED)) ;if(NULL == p_temp_used){return NULL ;} p_temp_used->begin = now_free->begin ;p_temp_used->end = now_free->begin + sizeof(TypeData)*size - 1 ;p_temp_used->mem_length = size ;p_temp_used->next = NULL ;p_used->next = p_temp_used ;printf("该次申请的内存块的地址为:%d ~ %p  长度为:%d\n\n",p_temp_used->begin,p_temp_used->end , size); /*直接在原来的节点上修改,把余下的空间直接放到该节点处*/now_free->mem_length = now_free->mem_length - size ;now_free->begin = now_free->begin + sizeof(TypeData)*size  ;return return_temp ;}//if(0 < distance) /*这块内存的大小正好与用户需求的一样*/ if(0 == distance){/*该节点处于尾节点*/if(NULL == now_free->next){now_free->uplink->next = NULL ;return_temp = now_free->begin ;/*把该内存块,挂载到used链表上去*/p_used = head_used ;/*找到末尾节点*/while(NULL != p_used->next ){p_used = p_used->next ;} p_temp_used = (USED*)malloc(sizeof(USED)) ;if(NULL == p_temp_used){return NULL ;} p_temp_used->begin = now_free->begin ;p_temp_used->end = now_free->begin + sizeof(TypeData)*size - 1 ;p_temp_used->mem_length = size ;p_temp_used->next = NULL ;p_used->next = p_temp_used ;printf("该次申请的内存块的地址为:%p ~ %p  长度为:%d\n\n",p_temp_used->begin,p_temp_used->end , size); /*直接释放该节点*/free(now_free) ;return return_temp ;}//if((NULL == now_free->next))/*该节点没有处于尾节点*/if(NULL != now_free->next){/*直接删除该节点*/now_free->uplink->next = now_free->next ;now_free->next->uplink = now_free->uplink ;return_temp = now_free->begin ;/*把该内存块,挂载到used链表上去*/p_used = head_used ;/*找到末尾节点*/while(NULL != p_used->next ){p_used = p_used->next ;} p_temp_used = (USED*)malloc(sizeof(USED)) ;if(NULL == p_temp_used){return NULL ;} p_temp_used->begin = now_free->begin ;p_temp_used->end = now_free->begin + sizeof(TypeData)*size - 1 ;p_temp_used->mem_length = size ;p_temp_used->next = NULL ;p_used->next = p_temp_used ;printf("该次申请的内存块的地址为:%p ~ %p  长度为:%d\n\n",p_temp_used->begin,p_temp_used->end , size); /*直接释放该节点*/free(now_free) ;return return_temp ;}// if(NULL != now_free->next)}// if(0 == distance)}/*功能:如果指针p为空,则什么都不做,    指针p指向的地址必须是min_malloc分配的地址,否则异常。返回值:0 释放正常1 出现错误*/ int min_free(const TypeData *p){/*暂存used链表的头结点*/USED *temp_used = head_used ; USED *last_temp = temp_used ; USED *now_used = NULL ;  /*暂存free链表的头接点*/ FREE *temp_free = NULL  ; FREE *new_free_node = NULL ; /*如果该要释放的地址为0*/if(NULL == p){return 1 ; } /*接下来要看这个地址是不是上面min_malloc函数分配的内存*/while(NULL != temp_used){if(temp_used->begin == p){break ;}last_temp = temp_used ;temp_used = temp_used->next ;}/*该地址不是min_malloc函数分配的地址*/if(NULL == temp_used){return 1 ;}now_used = temp_used ;/*现在原来的used链表中删除*//*如果是used链表的最后一个节点*/if(NULL == now_used->next){last_temp->next = NULL ;}/*如果是used链表的中间节点*/if(NULL != now_used->next){last_temp->next = now_used->next ;}/*接下来把释放的节点,插入到free链表中去*//*首先判断这次释放的内存,在free链表中有没有与其地址挨着的节点,如果有则进行合并*//*在used链表中进行查找*/temp_free = head_free->next;while(NULL != temp_free){/*头尾相连*/if(now_used->begin == (temp_free->end + sizeof(TypeData))){/*内存长度相加*/temp_free->mem_length = temp_free->mem_length + now_used->mem_length ;/*end地址要向后移动*/ temp_free->end = temp_free->begin + sizeof(TypeData)*temp_free->mem_length - 1 ;printf("%p ~ %p 地址释放成功\n\n",now_used->begin,now_used->end) ;free(now_used) ;return 0 ;} if((now_used->end + +sizeof(TypeData)) == temp_free->begin){/*内存长度相加*/temp_free->mem_length = temp_free->mem_length + now_used->mem_length ;/*begin地址要向前移动*/temp_free->begin = temp_free->end - sizeof(TypeData)*temp_free->mem_length + 1 ;printf("%p ~ %p 地址释放成功\n\n",now_used->begin,now_used->end) ;free(now_used) ;return 0 ;} temp_free = temp_free->next ;} //while(NULL != temp_free)/*释放的地址不能合并*/new_free_node = (FREE*)malloc(sizeof(FREE)) ;new_free_node->mem_length = now_used->mem_length ;new_free_node->begin = now_used->begin ;new_free_node->end = now_used->end ;new_free_node->next = NULL ;/*找到尾节点*/temp_free = head_free->next;while(NULL != temp_free->next){temp_free = temp_free->next ; } /*插入到free链表的尾部*/temp_free->next = new_free_node ;new_free_node->uplink = temp_free ;printf("%p ~ %p 地址释放成功\n\n",now_used->begin,now_used->end) ;free(now_used) ; return 0 ;} int main(){int result = 0 ;TypeData *applay_p1 = NULL ; TypeData *applay_p2 = NULL ; TypeData *applay_p3 = NULL ; TypeData *applay_p4 = NULL ; TypeData *start = NULL  ;result = min_init(&start , MEM_POOL_LENGTH) ;if(0 != result){printf("初始化内存管理器失败!\n") ;return 0 ; }applay_p1 = min_malloc(50) ;if(NULL == applay_p1) {printf("applay_1申请内存失败\n\n") ; return 0 ; }applay_p2 = min_malloc(20) ;if(NULL == applay_p2) {printf("applay_2申请内存失败\n\n") ; return 0 ; }applay_p3 = min_malloc(100) ;if(NULL == applay_p3) {printf("applay_3申请内存失败\n\n") ; return 0 ; }applay_p4 = min_malloc(5) ;if(NULL == applay_p4) {printf("applay_4申请内存失败\n\n") ; return 0  ;}result = min_free(applay_p2) ;if(0 != result){printf("applay_p2释放内存失败\n\n") ;}applay_p2 = min_malloc(60) ;if(NULL == applay_p2) {printf("applay_2申请内存失败\n\n") ; return 0 ; }return 0 ;}





0 0
原创粉丝点击