1.簡介
內存管理:指軟件運行時對計算機內存資源的分配和使用的技術。其最主要的目的是如何高效,快速的分配,并且在適當的時候釋放和回收內存資源。 內存管理的實現方法有很多種,最終都是要實現兩個函數: malloc 和 free。
malloc :函數用于內存申請;
free: 函數用于內存釋放。
1.1 分塊式內存管理原理
由上圖可知,分塊式內存管理由內存池和內存管理表兩部分組成。內存池被等分為 n塊,對應的內存管理表,大小也為 n,內存管理表的每一個項對應內存池的一塊內存。
內存管理表的項值代表的意義:當該項值為 0 的時候,代表對應的內存塊未被占用;當該項值非零的時候,代表該項對應的內存塊已經被占用,其數值則代表被連續占用的內存塊數。
比如:某項值為 10,那么說明包括本項對應的內存塊在內,總共分配了 10 個內存塊給外部的某個指針。內寸分配方向如圖所示,是從頂—>底的分配方向。即首先從最末端開始找空內存。當內存管理剛初始化的時候,內存表全部清零,表示沒有任何內存塊被占用。
1.2 分配原理
當指針 p 調用 malloc 申請內存的時候,先判斷 p 要分配的內存塊數(m),然后從第 n 項開始,向下查找,直到找到 m 塊連續的空內存塊(即對應內存管理表項為 0),然后將這 m 個內存管理表項的值都設置為 m(標記被占用),最后,把最后的這個空內存塊的地址返回指針 p,完成一次分配。
注:如果當內存不夠的時候(找到最后也沒找到連續的 m 塊空閑內存),則返回 NULL 給 p,表示分配失敗。
1.2 釋放原理
當 p 申請的內存用完,需要釋放的時候,調用 free 函數實現。 free 函數先判斷 p 指向的內存地址所對應的內存塊,然后找到對應的內存管理表項目,得到 p 所占用的內存塊數目 m(內存管理表項目的值就是所分配內存塊的數目),將這 m 個內存管理表項目的值都清零,標記釋放,完成一次內存釋放。
2.軟件分析
頭文件:
#ifndef __MALLOC_H
#define __MALLOC_H
#include "stm32f10x.h"
#ifndef NULL
#define NULL 0
#endif
//內存參數設定.
#define MEM_BLOCK_SIZE 32 //內存塊大小為32字節
#define MEM_MAX_SIZE 42*1024 //最大管理內存 42K
#define MEM_ALLOC_TABLE_SIZE MEM_MAX_SIZE/MEM_BLOCK_SIZE //內存表大小
//內存管理控制器
struct _m_mallco_dev
{
void (*init)(void); //初始化
u8 (*perused)(void); //內存使用率
u8 *membase; //內存池
u16 *memmap; //內存管理狀態表
u8 memrdy; //內存管理是否就緒
};
extern struct _m_mallco_dev mallco_dev; //在mallco.c里面定義
void mymemset(void *s,u8 c,u32 count); //設置內存
void mymemcpy(void *des,void *src,u32 n);//復制內存
void mem_init(void); //內存管理初始化函數(外/內部調用)
u32 mem_malloc(u32 size); //內存分配(內部調用)
u8 mem_free(u32 offset); //內存釋放(內部調用)
u8 mem_perused(void); //得內存使用率(外/內部調用)
////////////////////////////////////////////////////////////////////////////////
//用戶調用函數
void myfree(void *ptr); //內存釋放(外部調用)
void *mymalloc(u32 size); //內存分配(外部調用)
void *myrealloc(void *ptr,u32 size); //重新分配內存(外部調用)
#endif
參考例程:
#include "malloc.h"
//內存池(4字節對齊)
__align(4) u8 membase[MEM_MAX_SIZE]; //SRAM內存池
//內存管理表
u16 memmapbase[MEM_ALLOC_TABLE_SIZE]; //SRAM內存池MAP
//內存管理參數
const u32 memtblsize=MEM_ALLOC_TABLE_SIZE; //內存表大小
const u32 memblksize=MEM_BLOCK_SIZE; //內存分塊大小
const u32 memsize=MEM_MAX_SIZE; //內存總大小
//內存管理控制器
struct _m_mallco_dev mallco_dev=
{
mem_init, //內存初始化
mem_perused, //內存使用率
membase, //內存池
memmapbase, //內存管理狀態表
0, //內存管理未就緒
};
//復制內存
//*des:目的地址
//*src:源地址
//n:需要復制的內存長度(字節為單位)
void mymemcpy(void *des,void *src,u32 n)
{
u8 *xdes=des;
u8 *xsrc=src;
while(n--)
*xdes++=*xsrc++;
}
//設置內存
//*s:內存首地址
//c :要設置的值
//count:需要設置的內存大小(字節為單位)
void mymemset(void *s,u8 c,u32 count)
{
u8 *xs = s;
while(count--)
*xs++=c;
}
//內存管理初始化
void mem_init(void)
{
mymemset(mallco_dev.memmap, 0,memtblsize*2);//內存狀態表數據清零
mymemset(mallco_dev.membase, 0,memsize); //內存池所有數據清零
mallco_dev.memrdy=1; //內存管理初始化OK
}
//獲取內存使用率
//返回值:使用率(0~100)
u8 mem_perused(void)
{
u32 used=0;
u32 i;
for(i=0;i { if(mallco_dev.memmap[i]) used++; } return (used*100)/(memtblsize); } //內存分配(內部調用) //memx:所屬內存塊 //size:要分配的內存大小(字節) //返回值:0XFFFFFFFF,代表錯誤;其他,內存偏移地址 u32 mem_malloc(u32 size) { signed long offset=0; u16 nmemb; //需要的內存塊數 u16 cmemb=0;//連續空內存塊數 u32 i; if(!mallco_dev.memrdy) mallco_dev.init(); //未初始化,先執行初始化 if(size==0) return 0XFFFFFFFF; //不需要分配 nmemb=size/memblksize; //獲取需要分配的連續內存塊數 if(size%memblksize) nmemb++; for(offset=memtblsize-1;offset>=0;offset--) //搜索整個內存控制區 { if(!mallco_dev.memmap[offset]) cmemb++; //連續空內存塊數增加 else cmemb=0; //連續內存塊清零 if(cmemb==nmemb) //找到了連續nmemb個空內存塊 { for(i=0;i { mallco_dev.memmap[offset+i]=nmemb; } return (offset*memblksize); //返回偏移地址 } } return 0XFFFFFFFF;//未找到符合分配條件的內存塊 } //釋放內存(內部調用) //offset:內存地址偏移 //返回值:0,釋放成功;1,釋放失敗; u8 mem_free(u32 offset) { int i; if(!mallco_dev.memrdy)//未初始化,先執行初始化 { mallco_dev.init(); return 1;//未初始化 } if(offset { int index=offset/memblksize; //偏移所在內存塊號碼 int nmemb=mallco_dev.memmap[index]; //內存塊數量 for(i=0;i { mallco_dev.memmap[index+i]=0; } return 0; } else return 2;//偏移超區了. } //釋放內存(外部調用) //ptr:內存首地址 void myfree(void *ptr) { u32 offset; if(ptr==NULL) return;//地址為0. offset=(u32)ptr-(u32)mallco_dev.membase; mem_free(offset); //釋放內存 } //分配內存(外部調用) //size:內存大小(字節) //返回值:分配到的內存首地址. void *mymalloc(u32 size) { u32 offset; offset=mem_malloc(size); if(offset==0XFFFFFFFF) return NULL; else return (void*)((u32)mallco_dev.membase+offset); } //重新分配內存(外部調用) //*ptr:舊內存首地址 //size:要分配的內存大小(字節) //返回值:新分配到的內存首地址. void *myrealloc(void *ptr,u32 size) { u32 offset; offset=mem_malloc(size); if(offset==0XFFFFFFFF) return NULL; else { mymemcpy((void*)((u32)mallco_dev.membase+offset),ptr,size); //拷貝舊內存內容到新內存 myfree(ptr); //釋放舊內存 return (void*)((u32)mallco_dev.membase+offset); //返回新內存首地址 } } 主函數測試: #include "led.h" #include "delay.h" #include "sys.h" #include "usart.h" #include "lcd.h" #include "key.h" #include "malloc.h" #include "usmart.h" int main(void) { u8 key; u8 i=0; u8 *p=0; u8 *tp=0; u8 paddr[18]; //存放P Addr:+p地址的ASCII值 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 設置中斷優先級分組2 delay_init(); //延時函數初始化 uart_init(9600); //串口初始化為9600 LED_Init(); //初始化與LED連接的硬件接口 LCD_Init(); //初始化LCD usmart_dev.init(72); //初始化USMART KEY_Init(); //按鍵初始化 mem_init(); //初始化內存池 POINT_COLOR=RED;//設置字體為紅色 LCD_ShowString(60,50,200,16,16,"Mini STM32"); LCD_ShowString(60,70,200,16,16,"MALLOC TEST"); LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK"); LCD_ShowString(60,110,200,16,16,"2014/3/12"); LCD_ShowString(60,130,200,16,16,"KEY0:Malloc"); LCD_ShowString(60,150,200,16,16,"KEY1:Write Data"); LCD_ShowString(60,170,200,16,16,"WK_UP:Free"); POINT_COLOR=BLUE;//設置字體為藍色 LCD_ShowString(60,190,200,16,16,"SRAM USED: %"); while(1) { key=KEY_Scan(0);//不支持連按 switch(key) { case 0: //沒有按鍵按下 break; case 1: //KEY0按下 p=mymalloc(2048); //申請2K字節 if(p!=NULL) sprintf((char*)p,"Memory Malloc Test%03d",i);//向p寫入一些內容 break; case 2: //KEY1按下 if(p!=NULL) { sprintf((char*)p,"Memory Malloc Test%03d",i);//更新顯示內容 LCD_ShowString(60,250,200,16,16,p); //顯示P的內容 } break; case 3: //WK_UP按下 myfree(p); //釋放內存 p=0; //指向空地址 break; } if(tp!=p) { tp=p; sprintf((char*)paddr,"P Addr:0X%08X",(u32)tp); LCD_ShowString(60,230,200,16,16,paddr); //顯示p的地址 if(p)LCD_ShowString(60,250,200,16,16,p);//顯示P的內容 else LCD_Fill(60,250,239,266,WHITE); //p=0,清除顯示 } delay_ms(10); i++; if((i%20)==0)//DS0閃爍. { LCD_ShowNum(60+80,190,mem_perused(),3,16);//顯示內存使用率 LED0=!LED0; } } } 參考: 1.原子庫函數教程 2.STM32-內存管理
上一篇:STM32學習筆記一一UCOSII(1)
下一篇:STM32學習筆記一一DMA傳輸
推薦閱讀
史海拾趣
隨著全球化進程的加速,Conexcon Group積極實施國際化戰略,將業務拓展至海外市場。公司通過在海外設立研發中心和生產基地,進一步提升了自身的研發能力和生產效率。同時,公司還加強了與國際知名品牌的合作,通過共同推廣和營銷活動,提升了自身品牌在國際市場的知名度和影響力。這些舉措不僅為公司帶來了豐厚的利潤回報,也為公司的長遠發展奠定了堅實的基礎。
隨著全球化進程的加速,Conexcon Group積極實施國際化戰略,將業務拓展至海外市場。公司通過在海外設立研發中心和生產基地,進一步提升了自身的研發能力和生產效率。同時,公司還加強了與國際知名品牌的合作,通過共同推廣和營銷活動,提升了自身品牌在國際市場的知名度和影響力。這些舉措不僅為公司帶來了豐厚的利潤回報,也為公司的長遠發展奠定了堅實的基礎。
Array Microsystems Inc公司自創立之初,便專注于陣列傳感器技術的研發。在成立初期,公司面臨資金短缺和技術瓶頸的雙重挑戰。然而,通過不懈的努力和持續的技術創新,Array Microsystems Inc成功研發出了一款高靈敏度、低功耗的陣列傳感器。這一突破性的技術不僅填補了市場的空白,還為公司帶來了可觀的利潤。隨著產品的推廣和應用,Array Microsystems Inc逐漸在電子行業中嶄露頭角。
ARCOL公司的創立,標志著電子行業中一顆新星的誕生。在公司成立之初,ARCOL就專注于電子元器件的研發和生產。憑借創始團隊深厚的技術背景和敏銳的市場洞察力,公司成功開發出了一系列高質量的電子元器件產品,并很快在市場上贏得了良好的口碑。初步的成功為ARCOL公司的后續發展奠定了堅實的基礎。
隨著時間的推移,Cardinal不斷推出新的產品系列以滿足市場需求。2013年,公司推出了CJ速差器系列,這一系列產品以其高性能和穩定性受到了市場的廣泛好評。隨后,在2015年,CJ系列被移植到2.5×2.0封裝尺寸,進一步提高了產品的集成度和可靠性。這些產品系列的拓展與升級不僅豐富了公司的產品線,也為客戶提供了更多的選擇。
為了進一步提升企業的競爭力和市場份額,振華積極實施國際化戰略。公司加強與國外企業的合作與交流,積極參與國際市場競爭,通過引進外資、設立海外研發機構等方式,不斷拓展海外市場。同時,振華還注重提升產品的國際競爭力,加強與國際標準的對接和認證工作,確保產品能夠滿足不同國家和地區的市場需求。
本帖最后由 paulhyde 于 2014-9-15 02:59 編輯 請教各位電子設計競賽過來人,做控制類的題目需要準備什么樣的模塊?或者傳感器模塊? 謝謝啦。 [ 本帖最后由 open82977352 于 2010-2-2 19:50 編輯 ] … 查看全部問答∨ |
|
我是四川人,目前在上海工作,最近打算回成都找個工作。 簡單介紹一下自己。名校碩士畢業,三年vxworks設備驅動及DSP(TI C6000系列)軟件開發經驗,擅長數字信號處理,數值計算方面的算法開發,數模電路有些基礎,但 ...… 查看全部問答∨ |
1. ; 文件名:TEST4.S 2. ; 功能:通過查表實現程序散轉 3. ; 說明:使用ARMulate軟件仿真調試 4. NumCon EQU 0x40003001 ; 定義變量NumCn ...… 查看全部問答∨ |
這個問題我已google,baidu之。。還是不是很明白。。我剛涉及到驅動開發這一塊內容。。希望能得到大家通俗的解釋。。。不要給我google和baidu出的答案。。… 查看全部問答∨ |
請教: 我們公司想找一家公司開一塊電腦主板! 請各位大哥一些有這方面能力的公司! QQ:19335776 EMAIL:LSH9982008@163.COM 謝謝!… 查看全部問答∨ |
一早找到HT7333代替BL8505,HT7333的1、3腳分別接到C7兩端(其中1腳接到C7的接地端),2腳接到C4的正端(在PCB版上靠近R14),L1不接。 就穩定的提供了3.3V的電壓。 以前講過:1117- ...… 查看全部問答∨ |
NAND01G-B datasheet中怎么沒有命令寄存器,數據寄存器,地址寄存器的內存映射 dsp通過emifa與nandflash連接,nandflash型號是NAND01GW3A. 可是datasheet中怎么沒有命令寄存器,數據寄存器,地址寄存器的內存映射地址.… 查看全部問答∨ |