打印
[STM32F4]

【转】STM32F4-内存管理

[复制链接]
866|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
说书先生|  楼主 | 2016-11-3 18:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

一、简介:

    对于内存的管理主要是用来管理MCU在运行过程中内存资源的分配和使用问题,主要解决的问题是如何高效和快速的分配,并在适当时候回收内存资源,内存管理的方法也有很多种,但是最终都是在解决两个函数:malloc(内存申请)和free(内存释放)。

二、分块式内存管理原理

    存储方式:在这里介绍有关分块式内存管理的原理,对于分块式内存管理由内存池和内存管理表两部分组成,内存池被等分为n块,对应内存管理表大小也为n,内存管理表的一项对应内存池的一块内存。

    内存管理表:当内存管理表中的该项值为0时,表示该块内存未被占用,当该项值不为0时表示该项对应的内存块已被占用,而其值表示被连续占用的内存块数,例如如果该项值为10,则表示有连续的10块内存被占用。

    内存分配:对于内存的分配,内存分配方向为从内存池顶部向底部分配。在内存初始化后内存管理表中的值都为0,表示没有内存被占用。

三、分块式内存管理的内存分配原理

    当指针p调用malloc函数分配内存的时候,首先根据需要内存大小判断需要的内存块数目,例如需要m个内存块,然后从n项开始向下查找,如果有连续的m块内存没有被占用(即内存管理表中的值为0),则将这连续的m块内存对应的内存管理表内存设置为m,标志该段内存被占用。再将最后为空内存的那个内存块地址返回给p,完成一次内存的分配!如果遍历这个内存池都没有发现需要的内存大小,内存分配失败。

四、分块式内存管理的内存释放原理

    当需要释放内存时,p调用free函数,free函数首先判断p指向的地址所在的内存池,通过内存池找到对应的内存管理表项,取得内存管理表项中的值m,将这连续的m个内存管理表项清0,完成一次内存释放。


沙发
说书先生|  楼主 | 2016-11-3 18:56 | 只看该作者

五、代码体现

1、内存管理控制器:

[cpp] view plain copy
print?


  • //内存管理控制器  
  • struct _m_mallco_dev  
  • {  
  •     void (*init)(u8);               //初始化  
  •     u8 (*perused)(u8);                  //内存使用率  
  •     u8 *membase[SRAMBANK];              //内存池 管理SRAMBANK个区域的内存  
  •     u16 *memmap[SRAMBANK];              //内存管理状态表  
  •     u8  memrdy[SRAMBANK];               //内存管理是否就绪  
  • };  

2、内存管理和相关设置:

[cpp] view plain copy
print?


  • //内存池(32字节对齐)  
  • __align(32) u8 mem1base[MEM1_MAX_SIZE];                                 //内部SRAM内存池  
  • __align(32) u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000)));                 //外部SRAM内存池  
  • __align(32) u8 mem3base[MEM3_MAX_SIZE] __attribute__((at(0X10000000)));                 //内部CCM内存池  
  • //内存管理表  
  • u16 mem1mapbase[MEM1_ALLOC_TABLE_SIZE];                         //内部SRAM内存池MAP  
  • u16 mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X68000000+MEM2_MAX_SIZE)));   //外部SRAM内存池MAP  
  • u16 mem3mapbase[MEM3_ALLOC_TABLE_SIZE] __attribute__((at(0X10000000+MEM3_MAX_SIZE)));   //内部CCM内存池MAP  
  • //内存管理参数         
  • const u32 memtblsize[SRAMBANK]={MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE,MEM3_ALLOC_TABLE_SIZE}; //内存表大小  
  • const u32 memblksize[SRAMBANK]={MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE,MEM3_BLOCK_SIZE};           //内存分块大小  
  • const u32 memsize[SRAMBANK]={MEM1_MAX_SIZE,MEM2_MAX_SIZE,MEM3_MAX_SIZE};                //内存总大小  

3、内存管理控制器设定:

[cpp] view plain copy
print?


  • //内存管理控制器  
  • struct _m_mallco_dev mallco_dev=  
  • {  
  •     my_mem_init,                        //内存初始化  
  •     my_mem_perused,                     //内存使用率  
  •     mem1base,mem2base,mem3base,             //内存池  
  •     mem1mapbase,mem2mapbase,mem3mapbase,            //内存管理状态表  
  •     0,0,0,                          //内存管理未就绪  
  • };  

4、内存管理的基本函数:

[cpp] view plain copy
print?


  • //复制内存  
  • //n:需要复制的内存长度(单位字节)  
  • void mymemcpy(void *des,void *src,u32 n)   
  • {   
  •     u8 *xdes=des;  
  •     u8 *xsrc=src;   
  •     while(n--)*xdes++=*xsrc++;   
  • }   
  • //设置内存  
  • //count:需要设置的内存大小(字节为单位)  
  • void mymemset(void *s,u8 c,u32 count)   
  • {   
  •     u8 *xs = s;   
  •     while(count--)*xs++=c;   
  • }  


使用特权

评论回复
板凳
说书先生|  楼主 | 2016-11-3 18:58 | 只看该作者

5、内存初始化;

[cpp] view plain copy
print?


  • //内存管理初始化   
  • //memx:所属内存块  
  • void my_mem_init(u8 memx)   
  • {   
  •         mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);    //内存状态表数据清零   
  •     mymemset(mallco_dev.membase[memx], 0,memsize[memx]);        //内存池所有数据清零   
  •     mallco_dev.memrdy[memx]=1;                  //内存管理初始化OK   
  • }   

6、内存使用率获取:

[cpp] view plain copy
print?


  • //获取内存使用率  
  • //memx:所属内存块  
  • //返回值:使用率(0~100)  
  • u8 my_mem_perused(u8 memx)   
  • {   
  •     u32 used=0;   
  •     u32 i;   
  •     for(i=0;i<memtblsize[memx];i++)   
  •     {   
  •         if(mallco_dev.memmap[memx])used++;   
  •     }   
  •     return (used*100)/(memtblsize[memx]);   
  • }   

7、内存分配:

[cpp] view plain copy
print?


  • //内存分配(内部调用)  
  • //memx:所属内存块  
  • //size:要分配的内存大小(字节)  
  • //返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址   
  • u32 my_mem_malloc(u8 memx,u32 size)   
  • {   
  •     signed long offset=0;   
  •     u32 nmemb;  //需要的内存块数   
  •     u32 cmemb=0;//连续空内存块数  
  •     u32 i;   
  •     if(!mallco_dev.memrdy[memx])mallco_dev.init(memx);//未初始化,先执行初始化   
  •     if(size==0)return 0XFFFFFFFF;//不需要分配  
  •     nmemb=size/memblksize[memx];    //获取需要分配的连续内存块数  
  •     if(size%memblksize[memx])nmemb++;   
  •     for(offset=memtblsize[memx]-1;offset>=0;offset--)//搜索整个内存控制区   
  •     {      
  •         if(!mallco_dev.memmap[memx][offset])cmemb++;//连续空内存块数增加  
  •         else cmemb=0;                               //连续内存块清零  
  •         if(cmemb==nmemb)                            //找到了连续nmemb个空内存块  
  •         {  
  •             for(i=0;i<nmemb;i++)                             //标注内存块非空   
  •             {   
  •                 mallco_dev.memmap[memx][offset+i]=nmemb;   
  •             }   
  •             return (offset*memblksize[memx]);//返回偏移地址   
  •         }  
  •     }   
  •     return 0XFFFFFFFF;//未找到符合分配条件的内存块   
  • }   
  •   
  • //分配内存(外部调用)  
  • //memx:所属内存块  
  • //size:内存大小(字节)  
  • //返回值:分配到的内存首地址.  
  • void *mymalloc(u8 memx,u32 size)   
  • {   
  •     u32 offset;     
  •     offset=my_mem_malloc(memx,size);                 
  •     if(offset==0XFFFFFFFF)return NULL;   
  •     else return (void*)((u32)mallco_dev.membase[memx]+offset);   
  • }   
  • //重新分配内存(外部调用)  
  • //memx:所属内存块  
  • //*ptr:旧内存首地址  
  • //size:要分配的内存大小(字节)  
  • //返回值:新分配到的内存首地址.  
  • void *myrealloc(u8 memx,void *ptr,u32 size)   
  • {   
  •     u32 offset;      
  •     offset=my_mem_malloc(memx,size);      
  •     if(offset==0XFFFFFFFF)return NULL;      
  •     else   
  •     {                                       
  •     mymemcpy((void*)((u32)mallco_dev.membase[memx]+offset),ptr,size);   //拷贝旧内存内容到新内存     
  •         myfree(memx,ptr);                           //释放旧内存  
  •         return (void*)((u32)mallco_dev.membase[memx]+offset);           //返回新内存首地址  
  •     }   
  • }  

8、内存释放:


[cpp] view plain copy
print?


  • //释放内存(内部调用)   
  • //memx:所属内存块  
  • //offset:内存地址偏移  
  • //返回值:0,释放成功;1,释放失败;   
  • u32 my_mem_free(u8 memx,u32 offset)   
  • {   
  •     int i;   
  •     if(!mallco_dev.memrdy[memx])//未初始化,先执行初始化  
  •     {  
  •         mallco_dev.init(memx);      
  •             return 0xFFFFFFFF;//未初始化   
  •         }   
  •     if(offset<memsize[memx])//偏移在内存池内.   
  •     {   
  •         int index=offset/memblksize[memx];          //偏移所在内存块号码   
  •         int nmemb=mallco_dev.memmap[memx][index];       //内存块数量  
  •         for(i=0;i<nmemb;i++)                     //内存块清零  
  •         {   
  •             mallco_dev.memmap[memx][index+i]=0;   
  •         }   
  •         return ((u32)memblksize[memx]*nmemb+offset);   
  •     }else return 0xFFFFFFFF;//偏移超区了.   
  • }   
  • //释放内存(外部调用)   
  • //memx:所属内存块  
  • //ptr:内存首地址   
  • void *myfree(u8 memx,void *ptr)   
  • {   
  •     u32 offset;     
  •     if(ptr==NULL)return NULL;//地址为0.   
  •     offset=(u32)ptr-(u32)mallco_dev.membase[memx];      
  •     mynmemb=my_mem_free(memx,offset);  
  •     if(mynmemb==0XFFFFFFFF) return NULL;  
  •     else return (void *)((u32)mallco_dev.membase[memx]+mynmemb);  


使用特权

评论回复
地板
说书先生|  楼主 | 2016-11-3 19:02 | 只看该作者
六、总结:
    对于学习完内存的分配,感觉对其利用还是有很多问题,需要一点点总结好,多利用;这只是一个基础的用法,对于内存的分配方式还有很多种。
    在生活当中慢慢会发现,越是显的高大上的道理越是没有多大的意义,很多真正有意义的道理都是显的那么的简单,如果思想和道理也可以向上抽象的话,我想越是向上抽象,越是最简单不过的道理和理论;把最简单的道理做到了,就可以说是不简单了!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

71

主题

191

帖子

0

粉丝