#ifndef __MALLOC_H #define __MALLOC_H #include "stm32f10x.h" ////////////////////////////////////////////////////////////////////////////////// //本程序只供學習使用,未經做者許可,不得用於其它任何用途 //ALIENTEK戰艦STM32開發板V3 //內存管理 驅動代碼 //正點原子@ALIENTEK //技術論壇:www.openedv.com //修改日期:2015/1/20 //版本:V1.0 //版權全部,盜版必究。 //Copyright(C) 廣州市星翼電子科技有限公司 2009-2019 //All rights reserved ////////////////////////////////////////////////////////////////////////////////// #ifndef NULL #define NULL 0 #endif //定義兩個內存池 #define SRAMIN 0 //內部內存池 #define SRAMEX 1 //外部內存池 #define SRAMBANK 2 //定義支持的SRAM塊數. //mem1內存參數設定.mem1徹底處於內部SRAM裏面. #define MEM1_BLOCK_SIZE 32 //內存塊大小爲32字節 #define MEM1_MAX_SIZE 35*1024 //最大管理內存 40K #define MEM1_ALLOC_TABLE_SIZE MEM1_MAX_SIZE/MEM1_BLOCK_SIZE //內存表大小 //mem2內存參數設定.mem2的內存池處於外部SRAM裏面 #define MEM2_BLOCK_SIZE 32 //內存塊大小爲32字節 #define MEM2_MAX_SIZE 800 *1024 //最大管理內存960K #define MEM2_ALLOC_TABLE_SIZE MEM2_MAX_SIZE/MEM2_BLOCK_SIZE //內存表大小 //內存管理控制器 struct _m_mallco_dev { void (*init)(u8); //初始化 u8 (*perused)(u8); //內存使用率 u8 *membase[SRAMBANK]; //內存池 管理SRAMBANK個區域的內存 u16 *memmap[SRAMBANK]; //內存管理狀態表 u8 memrdy[SRAMBANK]; //內存管理是否就緒 }; 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 my_mem_init(u8 memx); //內存管理初始化函數(外/內部調用) u32 my_mem_malloc(u8 memx,u32 size); //內存分配(內部調用) u8 my_mem_free(u8 memx,u32 offset); //內存釋放(內部調用) u8 my_mem_perused(u8 memx); //得到內存使用率(外/內部調用) //////////////////////////////////////////////////////////////////////////////// //用戶調用函數 void myfree(u8 memx,void *ptr); //內存釋放(外部調用) void *mymalloc(u8 memx,u32 size); //內存分配(外部調用) void *myrealloc(u8 memx,void *ptr,u32 size);//從新分配內存(外部調用) #endif
#include "malloc.h" ////////////////////////////////////////////////////////////////////////////////// //本程序只供學習使用,未經做者許可,不得用於其它任何用途 //ALIENTEK戰艦STM32開發板V3 //內存管理 驅動代碼 //正點原子@ALIENTEK //技術論壇:www.openedv.com //修改日期:2015/1/20 //版本:V1.0 //版權全部,盜版必究。 //Copyright(C) 廣州市星翼電子科技有限公司 2009-2019 //All rights reserved ////////////////////////////////////////////////////////////////////////////////// //內存池(32字節對齊) __align(32) u8 mem1base[MEM1_MAX_SIZE]; //內部SRAM內存池 __align(32) u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000))); //外部SRAM內存池 //內存管理表 u16 mem1mapbase[MEM1_ALLOC_TABLE_SIZE]; //內部SRAM內存池MAP u16 mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X68000000+MEM2_MAX_SIZE))); //外部SRAM內存池MAP //內存管理參數 const u32 memtblsize[SRAMBANK]={MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE}; //內存表大小 const u32 memblksize[SRAMBANK]={MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE}; //內存分塊大小 const u32 memsize[SRAMBANK]={MEM1_MAX_SIZE,MEM2_MAX_SIZE}; //內存總大小 //內存管理控制器 struct _m_mallco_dev mallco_dev= { my_mem_init, //內存初始化 my_mem_perused, //內存使用率 mem1base,mem2base, //內存池 mem1mapbase,mem2mapbase, //內存管理狀態表 0,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; } //內存管理初始化 //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 } //獲取內存使用率 //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][i])used++; } return (used*100)/(memtblsize[memx]); } //內存分配(內部調用) //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:所屬內存塊 //offset:內存地址偏移 //返回值:0,釋放成功;1,釋放失敗; u8 my_mem_free(u8 memx,u32 offset) { int i; if(!mallco_dev.memrdy[memx])//未初始化,先執行初始化 { mallco_dev.init(memx); return 1;//未初始化 } 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 0; }else return 2;//偏移超區了. } //釋放內存(外部調用) //memx:所屬內存塊 //ptr:內存首地址 void myfree(u8 memx,void *ptr) { u32 offset; if(ptr==NULL)return;//地址爲0. offset=(u32)ptr-(u32)mallco_dev.membase[memx]; my_mem_free(memx,offset); //釋放內存 } //分配內存(外部調用) //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); //返回新內存首地址 } }
戰艦板和迷你板的內存管理有一點差異,迷你板只管理內部沒有外部,思想徹底同樣 c++
1. 思想:將內存池分爲塊,首先定義每一個塊的字節數,和內存池的總字節數,用總字節數除以每一個塊的字節數獲得塊數數組
2. 內存池,實際上就是一個數組函數
3. 內存管理塊,實際也是一個數組,總元素個數爲內存塊數,每一個元素對應一個內存塊,該元素非零時表示該內存塊沒有被佔用學習
4. 將第一步中的信息用數組保存起來,方便後面的函數調用spa
5. 將內存抽象爲一個結構體,傳入的參數分別是,初始化函數,佔用率函數,兩個內存池(數組)的基地址,兩個內存管理狀態表(兩個u16數組),兩個內存池的就緒布爾值3d
6. 初始化函數,實際上就是將指定內存池(數組)內面的內容所有用0填充,將內存狀態表(u16數組)所有用0填充,而後將該內存池的就緒布爾變量置一code
7. 計算內存使用率,注意:獲得的是塊使用的比率,而不是字節使用的比率對象
8. 複製,就是按字節依次賦值內容blog
9. 從起始位置將連續count個字節的區域用c填充內存
10. 分配內存(內部調用),成功:返回相對於數組首地址的偏移地址。
->判斷指定的內存池是否已經初始化
->若傳入參數爲0,表示不須要分配,直接返回
->經過所需字節數對每一個塊的字節數分別取整,取餘獲得所需的連續塊數
->從最後一個塊往前面尋找所需的連續塊,例如所需的塊爲3,當找到連續2塊而,下一塊已經被使用時,則將已經找的的連續塊數清零,再在前面找連續的3塊
->返回的偏移地址爲所需連續塊的起始塊相對於內存池的偏移地址
->將即將用到的內存塊對應的內存管理表中的元素置爲所需的連續塊數
11. 分配內存,首先判斷偏移地址是否正確,而後返回連續塊的首地址
12. 擴大分配內存,首先分配一個指定的內存,再將舊內存裏面的內容拷貝到新內存(這裏感受戰艦的源碼有問題,舊的內存裏面原來沒有size個元素,卻拷貝size個元素到新的空間),
最後釋放舊的內存空間,返回新的內存(塊)首地址
13. 清除連續的內存塊,成功:返回0
->首先經過偏移地址除以每一個塊的字節數,獲得起始塊的序號
->讀取起始塊對應的內存控制表元素,獲得從起始塊開始共要清除多少個連續的塊
->所謂的清除,實際上只是將對應的內存控制表的元素清零,內存中的值未清零。
->爲某個對象分配元素時,是分配的連續塊,清除時,也是清除這幾個連續塊,不一樣對象佔用不一樣的連續塊,清除時,不會影響其餘對象。
14. 內存釋放函數,首先得出偏移地址,而後,調用上一步的函數釋放內存