基于STM32原子戰(zhàn)艦板內存管理源碼
*/
//復制內存,作用是將源地址的內容復制到目標地址
//*des:目的地址
//*src:源地址
//n:需要復制的內存長度(字節(jié)為單位)
void mymemcpy(void *des,void *src,u32 n)
{ //“void *des”無類型指針,不能指向具體的數(shù)據(jù),“void *des”無類型指針指向內存中的數(shù)據(jù)類型由用戶自己確定
u8 *xdes=des;//目標地址,“*xdes”轉換成u8類型,也可以理解為把目的地地址des存儲到xdes指針中
u8 *xsrc=src;
while(n--)*xdes++=*xsrc++;
}
//設置內存
//*s:內存首地址
//c :要設置的值
//count:需要設置的內存大小(字節(jié)為單位)
void mymemset(void *s,u8 c,u32 count)
{
u8 *xs = s;
while(count--)*xs++=c;
} //以*s為內存首地址的count個字節(jié)中,填充c,即把c寫入到*s為首地址的內存中,個數(shù)多少由count值決定
//內存管理初始化
//memx:所屬內存塊,要么SRAMEX==1(外部內存);要么SRAMIN(內部內存)==0
/*
const u32 memtblsize[2]={MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE};//內存管理表大小
const u32 memblksize[2]={MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE}; //內存分塊大小
const u32 memsize[2]={MEM1_MAX_SIZE,MEM2_MAX_SIZE}; //內存總大小
*/
void mem_init(u8 memx) //如“mem_init(SRAMIN);”表示內部內存塊
{ //memmap,是16位的,mymemset,設置是針對8位的,那么1個16位的數(shù)據(jù)是不是2個8位組成的???!
mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);//內存狀態(tài)表數(shù)據(jù)清零
//把u8類型的數(shù)據(jù)“0”填充到u16類型指針元素memmap[0]中(根據(jù)結構體定義“u16 *memmap[2]; ”),memmap[0]=mem1mapbase==1250,
//也就是說“mallco_dev.memmap[memx]”在這里表示1250個內部內存塊用以存儲u16類型指針,
//“memtblsize[memx]”是什么呢?memtblsize[memx]即memtblsize[0]==1250個內部內存管理表,
//而mallco_dev.memmap[memx]是16位的,為了將其全部清零,所以乘以2.
mymemset(mallco_dev.membase[memx], 0,memsize[memx]); //內存池所有數(shù)據(jù)清零
//memsize[0]==40K字節(jié)空間, mallco_dev.membase[memx]==40K字節(jié)空間,
mallco_dev.memrdy[memx]=1; //內存管理初始化OK
}
/*
*/
//獲取內存使用率
//memx:所屬內存塊,要么SRAMEX==1(外部內存);要么SRAMIN(內部內存)==0
//返回值:使用率(0~100)
u8 mem_perused(u8 memx)
{
u32 used=0;
u32 i;
for(i=0;i {
if(mallco_dev.memmap[memx][i])used++;
} //mallco_dev.memmap[memx][i]是二維數(shù)組。當內存塊初始化后該值為0,
return (used*100)/(memtblsize[memx]); //used*100,乘以100是將小數(shù)變成整數(shù)
}
//內存分配(內部調用)
//memx:所屬內存塊
//size:要分配的內存大小(字節(jié)數(shù))
//返回值:0XFFFFFFFF,代表錯誤;其他,內存偏移地址
//向memx存儲器申請size個字節(jié)的連續(xù)存儲空間,并將size個字節(jié)中首個字節(jié)的地址偏移值標注出來,注意是地址偏移值而不是地址。
u32 mem_malloc(u8 memx,u32 size)
{
signed long offset=0;
u16 nmemb; //需要的內存塊數(shù)
u16 cmemb=0;//連續(xù)空內存塊數(shù)
u32 i;
if(!mallco_dev.memrdy[memx])mallco_dev.init(memx);//未初始化,先執(zhí)行初始化
/*
“mallco_dev.init(memx);”是什么意思?mallco_dev.init(memx)是結構體變量mallco_dev的一個成員,本句中就是對結構體成員的引用,即執(zhí)行
mem_init(u8 memx)函數(shù)的意思;如何引用結構體中指向函數(shù)的指針變量成員?既然是指向函數(shù)的指針變量且有賦值,在引用時按照格式:
結構體變量名.指向函數(shù)的指針變量名(形參);
*/
if(size==0)return 0XFFFFFFFF;//不需要分配 memblksize[memx]==32
nmemb=size/memblksize[memx]; //獲取需要分配的連續(xù)內存塊數(shù)
/*
c語言規(guī)定:除法的運算結果與運算對象的數(shù)據(jù)類型有關,兩個數(shù)都是int則商(即結果)是int,若商(即結果)有小數(shù)則省略掉小數(shù)點部分。本例中
size和memblksize[memx]都是int,所以結果只能是int。假設size<32,則nmemb==0;
c語言規(guī)定取余運算的運算對象必須是int。當小數(shù)對大數(shù)取余時余(即結果)是小數(shù)本身;例如,在“if(size%memblksize[memx])nmemb++;”中 ,
假設size<32,則size%memblksize[memx]的結果是size值本身,所以執(zhí)行“nmemb++;”運算,這時運算結果是nmemb==1;如果size是32的整數(shù)倍則不執(zhí)行
“nmemb++;”運算;
memtblsize[0]==1250,memtblsize[1]==6250,
mallco_dev.memmap[memx][offset]是什么意思?
*/
if(size%memblksize[memx])nmemb++;
for(offset=memtblsize[memx]-1;offset>=0;offset--)//搜索整個內存控制區(qū)
{
if(!mallco_dev.memmap[memx][offset])cmemb++;//連續(xù)空內存塊數(shù)增加,offset從1249->0變化
/*
如,{ memmap[0][149],memmap[0][148],...memmap[0][1],memmap[0][0]};實際上可以把“mallco_dev.memmap[memx][offset]”視為具有1250個變量的
一維數(shù)組,每個元素對應的實際意義是對應的一個內存塊,順序是offset從1249(高)->0(低)變化;如果哪個變量等于0(即空閑)就執(zhí)行
“cmemb++;”操作,這樣就可以計算出連續(xù)空閑內存塊數(shù)cmemb;切記!目的是要獲取連續(xù)的空閑的內存塊數(shù)!這樣就必須結合下一句
“else cmemb=0;”來分析;如果沒有出現(xiàn)連續(xù)的空閑內存塊(即數(shù)組順序相連的變量值沒有出現(xiàn)類似“0,0,0,0,0”這樣的情況),程序會執(zhí)行下一語
句“else cmemb=0;”即把上面的“cmemb”統(tǒng)計值清零,這樣程序就會在for循環(huán)里面繼續(xù)尋找符合“if(cmemb==nmemb)”條件的狀態(tài)出現(xiàn),
如果for循環(huán)執(zhí)行完了還沒有出現(xiàn)符合“if(cmemb==nmemb)”條件的狀態(tài),則返回0XFFFFFFFF結束本函數(shù)表示沒有找到符合條件的內存塊。假
設:size=65,那么nmemb就是3即需要獲取連續(xù)3個內存塊來存放65個字節(jié),再假設數(shù)組順序相連的變量值出現(xiàn)了類似“0,0,0,0,0”這樣的情況(即有
連續(xù)4個空閑的內存塊),這時就出現(xiàn)了符合“if(cmemb==nmemb)”條件的狀態(tài),即當cmemb計數(shù)計到3的時候(即出現(xiàn)了連續(xù)相連的3個內存塊)就
符合“cmemb==nmemb”了,程序就自然進入“if(cmemb==nmemb)”語句。
offset*memblksize[memx]代表什么呢?offset的取值范圍是0-1249,memblksize[memx]代表每個內存塊的字節(jié)數(shù)即32,offset*memblksize[memx]就
是返回偏移地址值;也就是把連續(xù)空閑的內存塊對應的地址的首地址值標注出來。
*/
else cmemb=0; //連續(xù)內存塊清零
if(cmemb==nmemb) //找到了連續(xù)nmemb個空內存塊
{
for(i=0;i {
mallco_dev.memmap[memx][offset+i]=nmemb;
}
return (offset*memblksize[memx]);//返回偏移地址
}
}
return 0XFFFFFFFF;//未找到符合分配條件的內存塊
}
//釋放內存(內部調用)
//memx:所屬內存塊
//offset:內存地址偏移
//返回值:0,釋放成功;1,釋放失敗;
u8 mem_free(u8 memx,u32 offset)
{
int i;
if(!mallco_dev.memrdy[memx])//未初始化,先執(zhí)行初始化
{
mallco_dev.init(memx); //本句等價于“mem_init(memx);”
return 1;//未初始化
}
if(offset {
int index=offset/memblksize[memx]; //偏移所在內存塊號碼 memblksize[memx]==32,
int nmemb=mallco_dev.memmap[memx][index]; //內存塊數(shù)量
for(i=0;i {
mallco_dev.memmap[memx][index+i]=0;
}
return 0;
}else return 2;//偏移超區(qū)了.
}
//釋放內存(外部調用)
//memx:所屬內存塊
//ptr:內存首地址
void myfree(u8 memx,void *ptr)
{
u32 offset;
if(ptr==NULL)return;//地址為0.
offset=(u32)ptr-(u32)mallco_dev.membase[memx];
mem_free(memx,offset);//釋放內存
}
//分配內存(外部調用)
//memx:所屬內存塊
//size:內存大小(字節(jié))
//返回值:分配到的內存首地址.
//在memx存儲器中,找出size個字節(jié)的連續(xù)空閑的內存空間,并將連續(xù)空閑的內存空間指針值標注出來;返回值就是這個指針值
/*
mallco_dev.membase[memx]即mallco_dev.membase[0]代表MCU內部存儲器的40K字節(jié)中的第一個字節(jié)變量的地址,是u8類型指針變量,也就是說一個字節(jié)占用一個地址;換句話說,把內部存儲器的40K字節(jié)的地址定義為一個“u8 mem1base[MEM1_MAX_SIZE]”數(shù)組,指針類型數(shù)組“u8 *membase[2];”的賦值是{mem1base,mem2base},而“mem1base,mem2base”分別是內部內存池和外部內存池的數(shù)組名,各自首元素的地址亦是個指針常量;因為事先已經定義
“u8 mem1base[MEM1_MAX_SIZE]”即“u8 mem1base[40K];”。如何理解“(void*)((u32)mallco_dev.membase[memx]+offset); ”呢?
1),已經說過mallco_dev.membase[memx]是首個變量的地址即40k字節(jié)中首個字節(jié)的地址值;
2),“offset”是:向memx存儲器申請size個字節(jié)的連續(xù)空閑存儲空間,這個找到的連續(xù)空閑空間當中首個字節(jié)的地址偏移值就是offset,offset==32(將32個字節(jié)空間組成一個內存塊)*內存塊號(如,假設向內部存儲器申請64個字節(jié)的連續(xù)空閑存儲空間,通過“mem_malloc(memx,size); ”函數(shù)得到在第五個存儲塊開始有連續(xù)2個存儲快空閑可供使用(假設是5號和4號存儲快),因為每個存儲快有32個字節(jié)即有32個地址編號,4*32==128(這里的4是指第四塊),5*32==160(這里的5是指第五塊),那么這個160就是40K個字節(jié)編號當中的地址偏移值offset,即128-192號就是第四塊和第五塊內存塊所對應的指針編號);注意offset是地址偏移值而不是地址;為什么要引入地址偏移值這個概念呢?假設第一個字節(jié)的地址值是0x0000 6800,那么就知道(0x0000 6800+160)的值就是第五塊內存的指針。
3),“(u32)mallco_dev.membase[memx]”代表指針類型數(shù)組,意義是內部存儲器40K字節(jié)中的第一個字節(jié)變量的地址,原來存放的是u8類型數(shù)據(jù)的地址,現(xiàn)在強制類型轉換擴展為u32類型;
4),(void*)((u32)mallco_dev.membase[memx]+offset); 轉換為無類型指針,指針值是32位,由此可知,“void *mymalloc(u8 memx,u32 size)”函數(shù)的返回值就是一個指針,即形參size所指向的由高向低的首個指針值;“void *mymalloc(u8 memx,u32 size)”是個指針類型函數(shù),只能賦給指針。
*/
void *mymalloc(u8 memx,u32 size) //p=mymalloc(sramx,2048)
{
u32 offset;
offset=mem_malloc(memx,size);
if(offset==0XFFFFFFFF)return NULL;
else return (void*)((u32)mallco_dev.membase[memx]+offset);
}
//重新分配內存(外部調用)
//memx:所屬內存塊
//*ptr:舊內存首地址
//size:要分配的內存大小(字節(jié))
//返回值:新分配到的內存首地址.
void *myrealloc(u8 memx,void *ptr,u32 size)
{
u32 offset;
offset=mem_malloc(memx,size);
if(offset==0XFFFFFFFF)return NULL;
else
{
mymemcpy((void*)((u32)mallco_dev.membase[memx]+offset),ptr,size); //拷貝舊內存內容到新內存
// 把size個字節(jié)指針ptr復制到“((u32)mallco_dev.membase[memx]+offset)”,
myfree(memx,ptr); //釋放舊內存,因為在mem_malloc(memx,size)中已經將連續(xù)空閑內存塊標注為1(已被占用),清除掉原來的標記
return (void*)((u32)mallco_dev.membase[memx]+offset); //返回新內存首地址,無類型指針
}
}
頭文件:
#ifndef __MALLOC_H
#define __MALLOC_H
typedef unsigned long u32;
typedef unsigned short u16;
typedef unsigned char u8;
#ifndef NULL
#define NULL 0
#endif
#define SRAMIN 0 //內部內存池
#define SRAMEX 1 //外部內存池
//mem1內存參數(shù)設定.mem1完全處于內部SRAM里面
#define MEM1_BLOCK_SIZE 32 //內存塊大小為32字節(jié)
#define MEM1_MAX_SIZE 40*1024 //最大管理內存 40K
#define MEM1_ALLOC_TABLE_SIZE MEM1_MAX_SIZE/MEM1_BLOCK_SIZE //內存表大小
//mem2內存參數(shù)設定.mem2的內存池處于外部SRAM里面,其他的處于內部SRAM里面
#define MEM2_BLOCK_SIZE 32 //內存塊大小為32字節(jié)
#define MEM2_MAX_SIZE 200*1024 //最大管理內存200K
#define MEM2_ALLOC_TABLE_SIZE MEM2_MAX_SIZE/MEM2_BLOCK_SIZE //內存表大小
關鍵詞:
STM32原子戰(zhàn)艦板內存管
評論