基於STM32F429的內存管理

1.內存管理介紹

  內存管理,是指軟件運行時對計算機內存資源的分配和使用的技術。其最主要的目的是如
何高效,快速的分配,而且在適當的時候釋放和回收內存資源。 內存管理的實現方法有不少種,
他們其實最終都是要實現 2 個函數: malloc freemalloc 函數用於內存申請, free 函數用於
內存釋放。
             
c++

   從上圖能夠看出,分塊式內存管理由內存池和內存管理表兩部分組成。內存池被等分爲 n
塊,對應的內存管理表,大小也爲 n,內存管理表的每個項對應內存池的一塊內存。
內存管理表的項值表明的意義爲:當該項值爲 0 的時候,表明對應的內存塊未被佔用,當
該項值非零的時候,表明該項對應的內存塊已經被佔用,其數值則表明被連續佔用的內存塊數。
好比某項值爲 10,那麼說明包括本項對應的內存塊在內,總共分配了 10 個內存塊給外部的某
個指針。
內寸分配方向如圖所示,是從頂底的分配方向。即首先從最末端開始找空內存。當內存
管理剛初始化的時候,內存表所有清零,表示沒有任何內存塊被佔用。
分配原理
函數

  當指針 p 調用 malloc 申請內存的時候,先判斷 p 要分配的內存塊數(m),而後從第 n 項開 測試

,向下查找,直到找到 m 塊連續的空內存塊(即對應內存管理表項爲 0),而後將這 m 個內
存管理表項的值都設置爲 m(標記被佔用),最後,把最後的這個空內存塊的地址返回指針 p
完成一次分配。注意,若是當內存不夠的時候(找到最後也沒找到連續的 m 塊空閒內存),則
返回 NULL p
,表示分配失敗。
釋放原理
  
p 申請的內存用完,須要釋放的時候,調用 free 函數實現。 free 函數先判斷 p 指向的內
存地址所對應的內存塊,而後找到對應的內存管理表項目,獲得 p 所佔用的內存塊數目 m(內
存管理表項目的值就是所分配內存塊的數目),將這 m 個內存管理表項目的值都清零,標記釋
放,完成一次內存釋放。

該原理解釋要結合下面的內部調用函數理解
ui

2.代碼介紹

  該次程序 只實現了內部內存池的內存管理,還有外部內存池(SDRAM) 和CCM 內存池(此部分 SRAM 僅僅 CPU 能夠訪問)未實現,
但通常程序只要前者就夠了。內部內存池是STM32F4內部的處理芯片的RAM,STM32F429 自己自帶的 256K 字節內存 ,普通內存
spa

(地址從: 0X2000 0000 開始,共 192KB),這部份內存任何外設都能夠訪問 3d

 

內存管理的宏定義參數:即把160k的內存分爲64塊,每塊大小爲2560B指針

 

#define MEM1_BLOCK_SIZE            64                              //內存塊大小爲64字節
#define MEM1_MAX_SIZE            160*1024                          //最大管理內存 160K
#define MEM1_ALLOC_TABLE_SIZE    MEM1_MAX_SIZE/MEM1_BLOCK_SIZE     //內存表大小

 

管理結構體:由於是靜態分配的內存管理,因此用宏定義的結構體,動態分配的能力有限,弄不了。code

 

struct _m_mallco_dev 
{                                  
    uint8_t      *membase;                                //內存池 管理SRAMBANK個區域的內存
    uint32_t   *memmap;                                 //內存管理狀態表
    uint8_t    memrdy;                               //內存管理是否就緒
};

extern struct _m_mallco_dev malloc_handle2;

 

 

 

 

內存管理函數blog

 

extern void malloc_set(void *s,uint8_t c,uint32_t count);       //設置內存(基本函數)
extern void malloc_cpy(void *des,void *src,uint32_t n);        //複製內存(基本函數)



extern void malloc_Outfree(void *ptr);              //內存釋放(外部調用)
extern void *malloc_Outallot(uint32_t size);        //內存分配(外部調用)

//外部調用內部
extern uint32_t malloc_mem(uint32_t size);       //內存分配(內部調用)
extern uint8_t malloc_free(uint32_t offset);   //內存釋放(內部調用)


extern uint16_t malloc_perused(void) ;                     //得到內存使用率(外/內部調用) 
extern void malloc_init(void);                             //內存管理初始化函數(外/內部調用)

 

 

 

 

malloc.c程序,由原子的內存管理實驗原碼改制而來,有大幅度變化,只支持內部內存池,最好看看原子的實驗原碼,會有更深的瞭解,就不具體講解了。內存

 

/******************************僅用於內部存儲模塊SRAM*******************************************/
//內存池(32字節對齊)
 __align(32) uint8_t mem1base[MEM1_MAX_SIZE];                         //內部SRAM內存池

//內存管理表
 __align(32) uint32_t memmapbase[MEM1_ALLOC_TABLE_SIZE];            //內部SRAM內存池MAP

//內存管理參數
const uint32_t memtblsize=MEM1_ALLOC_TABLE_SIZE;                      //內存表大小
const uint32_t memblksize=MEM1_BLOCK_SIZE;                            //內存分塊大小
const uint32_t memsize=MEM1_MAX_SIZE;                                 //內存總大小

 struct _m_mallco_dev malloc_handle2=
{
    mem1base,
   memmapbase,
   0,    
};

//內存管理初始化  
//malloc_handle1內存管理結構體
void malloc_init()  
{  
      
    malloc_set(malloc_handle2.memmap,0,memtblsize*4);    //內存狀態表數據清零  
      malloc_handle2.memrdy=1;                                            //內存管理初始化OK   
  
}  

//獲取內存使用率
//malloc_handle1內存管理結構體
//返回值:使用率(擴大了10倍,0~1000,表明0.0%~100.0%)
uint16_t malloc_perused(void)  
{  
    uint32_t used=0;  
    uint32_t i;
        

    for(i=0;i<memtblsize;i++)  
    {  
                  
        if(malloc_handle2.memmap[i])
                {
                    used++; 
                
                }
                         
    } 
        
        printf("%u\n",used);
    return (used*1000)/(memtblsize);
}  


//複製內存
//*des:目的地址
//*src:源地址
//n:須要複製的內存長度(字節爲單位)
void malloc_cpy(void *des,void *src,uint32_t n)  
{  
    uint8_t *xdes=des;
      uint8_t *xsrc=src; 
    while(n--)
            *xdes++=*xsrc++;  
}  

//設置內存
//*s:內存首地址
//c :要設置的值
//count:須要設置的內存大小(字節爲單位)
void malloc_set(void *s,uint8_t c,uint32_t count)  
{  
    uint8_t *xs = s;  
    while(count--)
            *xs++=c;  
        
}    


//分配內存(外部調用)
//malloc_handle1內存管理結構體
//size:內存大小(字節)
//返回值:分配到的內存首地址.
void *malloc_Outallot(uint32_t size)
{  
    uint32_t offset; 
       
      offset=malloc_mem(size);      
  
    if(offset==0XFFFFFFFF)
            return NULL;  
        else
            return (void*)((uint32_t)malloc_handle2.membase+offset);
   
}  

//釋放內存(外部調用) 
//malloc_handle1內存管理結構體
//ptr:內存首地址 
void malloc_Outfree(void *ptr)
{
     uint32_t offset; 
   if(ptr==NULL)
         return;
    
   offset=(uint32_t )ptr-(uint32_t )malloc_handle2.membase;
   malloc_free(offset);       
       
}


//內存分配(內部調用)
//malloc_handle1內存管理結構體
//size:要分配的內存大小(字節)
//返回值:0XFFFFFFFF,表明錯誤;其餘,內存偏移地址 
uint32_t malloc_mem(uint32_t size)  
{  
    signed long offset=0;  
    uint32_t nmemb;                   //須要的內存塊數  
      uint32_t cmemb=0;              //連續空內存塊數
    uint32_t i;  
    if(!malloc_handle2.memrdy)
            malloc_init();               //未初始化,先執行初始化 
    if(size==0)
            return 0XFFFFFFFF;           //不須要分配
        //malloc_handle1->memmap=mem1mapbase;    
    nmemb=size/memblksize;           //獲取須要分配的連續內存塊數
    if(size%memblksize)
            nmemb++;  
    for(offset=memtblsize-1;offset>=0;offset--)//搜索整個內存控制區  
    {     
        if(!malloc_handle2.memmap[offset])
            cmemb++;                    //連續空內存塊數增長
        else 
            cmemb=0;                                    //連續內存塊清零
        if(cmemb==nmemb)                            //找到了連續nmemb個空內存塊
        {
            for(i=0;i<nmemb;i++)  //標註內存塊非空 
            {  
                malloc_handle2.memmap[offset+i]=nmemb;  
            }  
            return (offset*memblksize);//返回偏移地址  
        }
    }  
    return 0XFFFFFFFF;//未找到符合分配條件的內存塊  
}  

//釋放內存(內部調用) 
//malloc_handle1內存管理結構體
//offset:內存地址偏移
//返回值:0,釋放成功;1,釋放失敗;  
uint8_t malloc_free(uint32_t offset)  
{  
    int i;  
      int index=offset/memblksize;                       //偏移所在內存塊號碼  
    int nmemb=malloc_handle2.memmap[index];         //內存塊數量
    if(!malloc_handle2.memrdy)//未初始化,先執行初始化
      {
            malloc_init(); ;    
        return 1;                                    //未初始化  
    }  
    if(offset<=memsize)                              //偏移在內存池內. 
    {  
       
        for(i=0;i<nmemb;i++)                           //內存塊清零
        {  
            malloc_handle2.memmap[index+i]=NULL;  
        }  
        return 0;  
    }
        else 
            return 2;//偏移超區了.  
}

 

 

 

 

3.測試

測試代碼

  

 
 

uint8_t paddr[20]; //存放P Addr:+p地址的ASCII值
uint16_t memused=0;
uint8_t key;
uint8_t *p=0;
uint8_t i=0;



key=KEY_Scan(0); //按鍵掃描 switch(key) { case WKUP_PRES: { //printf("aa"); p=malloc_Outallot(2048);//申請2K字節 if(p!=NULL) sprintf((char*)p,"AAAAAAAA",i);//向p寫入一些內容 printf("寫入:%s", p); memused=malloc_perused(); sprintf((char*)paddr,"%d.%01d%%",memused/10,memused%10); printf("%s",paddr); break; } case KEY2_PRES: { malloc_Outfree(p);//釋放內存 printf("釋放:%s", p); p=0; //指向空地址 memused=malloc_perused(); sprintf((char*)paddr,"%d.%01d%%",memused/10,memused%10); printf("%s",paddr); break; } case KEY1_PRES: { break; } case KEY0_PRES: { break; } }

 

測試結果

 

4,注意事項

   申請的內存使用完後,必定要釋放掉,否則內存池會被寫爆。

  有不足之處請指正,謝謝閱讀,麻煩點贊支持。

相關文章
相關標籤/搜索