基于STM32原子戰艦板內存管理源碼
*/
//復制內存,作用是將源地址的內容復制到目標地址
//*des:目的地址
//*src:源地址
//n:需要復制的內存長度(字節為單位)
void mymemcpy(void *des,void *src,u32 n)
{ //“void *des”無類型指針,不能指向具體的數據,“void *des”無類型指針指向內存中的數據類型由用戶自己確定
u8 *xdes=des;//目標地址,“*xdes”轉換成u8類型,也可以理解為把目的地地址des存儲到xdes指針中
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;
} //以*s為內存首地址的count個字節中,填充c,即把c寫入到*s為首地址的內存中,個數多少由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位的數據是不是2個8位組成的?。?!
mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);//內存狀態表數據清零
//把u8類型的數據“0”填充到u16類型指針元素memmap[0]中(根據結構體定義“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]); //內存池所有數據清零
//memsize[0]==40K字節空間, mallco_dev.membase[memx]==40K字節空間,
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]是二維數組。當內存塊初始化后該值為0,
return (used*100)/(memtblsize[memx]); //used*100,乘以100是將小數變成整數
}
//內存分配(內部調用)
//memx:所屬內存塊
//size:要分配的內存大小(字節數)
//返回值:0XFFFFFFFF,代表錯誤;其他,內存偏移地址
//向memx存儲器申請size個字節的連續存儲空間,并將size個字節中首個字節的地址偏移值標注出來,注意是地址偏移值而不是地址。
u32 mem_malloc(u8 memx,u32 size)
{
signed long offset=0;
u16 nmemb; //需要的內存塊數
u16 cmemb=0;//連續空內存塊數
u32 i;
if(!mallco_dev.memrdy[memx])mallco_dev.init(memx);//未初始化,先執行初始化
/*
“mallco_dev.init(memx);”是什么意思?mallco_dev.init(memx)是結構體變量mallco_dev的一個成員,本句中就是對結構體成員的引用,即執行
mem_init(u8 memx)函數的意思;如何引用結構體中指向函數的指針變量成員?既然是指向函數的指針變量且有賦值,在引用時按照格式:
結構體變量名.指向函數的指針變量名(形參);
*/
if(size==0)return 0XFFFFFFFF;//不需要分配 memblksize[memx]==32
nmemb=size/memblksize[memx]; //獲取需要分配的連續內存塊數
/*
c語言規定:除法的運算結果與運算對象的數據類型有關,兩個數都是int則商(即結果)是int,若商(即結果)有小數則省略掉小數點部分。本例中
size和memblksize[memx]都是int,所以結果只能是int。假設size<32,則nmemb==0;
c語言規定取余運算的運算對象必須是int。當小數對大數取余時余(即結果)是小數本身;例如,在“if(size%memblksize[memx])nmemb++;”中 ,
假設size<32,則size%memblksize[memx]的結果是size值本身,所以執行“nmemb++;”運算,這時運算結果是nmemb==1;如果size是32的整數倍則不執行
“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--)//搜索整個內存控制區
{
if(!mallco_dev.memmap[memx][offset])cmemb++;//連續空內存塊數增加,offset從1249->0變化
/*
如,{ memmap[0][149],memmap[0][148],...memmap[0][1],memmap[0][0]};實際上可以把“mallco_dev.memmap[memx][offset]”視為具有1250個變量的
一維數組,每個元素對應的實際意義是對應的一個內存塊,順序是offset從1249(高)->0(低)變化;如果哪個變量等于0(即空閑)就執行
“cmemb++;”操作,這樣就可以計算出連續空閑內存塊數cmemb;切記!目的是要獲取連續的空閑的內存塊數!這樣就必須結合下一句
“else cmemb=0;”來分析;如果沒有出現連續的空閑內存塊(即數組順序相連的變量值沒有出現類似“0,0,0,0,0”這樣的情況),程序會執行下一語
句“else cmemb=0;”即把上面的“cmemb”統計值清零,這樣程序就會在for循環里面繼續尋找符合“if(cmemb==nmemb)”條件的狀態出現,
如果for循環執行完了還沒有出現符合“if(cmemb==nmemb)”條件的狀態,則返回0XFFFFFFFF結束本函數表示沒有找到符合條件的內存塊。假
設:size=65,那么nmemb就是3即需要獲取連續3個內存塊來存放65個字節,再假設數組順序相連的變量值出現了類似“0,0,0,0,0”這樣的情況(即有
連續4個空閑的內存塊),這時就出現了符合“if(cmemb==nmemb)”條件的狀態,即當cmemb計數計到3的時候(即出現了連續相連的3個內存塊)就
符合“cmemb==nmemb”了,程序就自然進入“if(cmemb==nmemb)”語句。
offset*memblksize[memx]代表什么呢?offset的取值范圍是0-1249,memblksize[memx]代表每個內存塊的字節數即32,offset*memblksize[memx]就
是返回偏移地址值;也就是把連續空閑的內存塊對應的地址的首地址值標注出來。
*/
else cmemb=0; //連續內存塊清零
if(cmemb==nmemb) //找到了連續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])//未初始化,先執行初始化
{
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]; //內存塊數量
for(i=0;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];
mem_free(memx,offset);//釋放內存
}
//分配內存(外部調用)
//memx:所屬內存塊
//size:內存大小(字節)
//返回值:分配到的內存首地址.
//在memx存儲器中,找出size個字節的連續空閑的內存空間,并將連續空閑的內存空間指針值標注出來;返回值就是這個指針值
/*
mallco_dev.membase[memx]即mallco_dev.membase[0]代表MCU內部存儲器的40K字節中的第一個字節變量的地址,是u8類型指針變量,也就是說一個字節占用一個地址;換句話說,把內部存儲器的40K字節的地址定義為一個“u8 mem1base[MEM1_MAX_SIZE]”數組,指針類型數組“u8 *membase[2];”的賦值是{mem1base,mem2base},而“mem1base,mem2base”分別是內部內存池和外部內存池的數組名,各自首元素的地址亦是個指針常量;因為事先已經定義
“u8 mem1base[MEM1_MAX_SIZE]”即“u8 mem1base[40K];”。如何理解“(void*)((u32)mallco_dev.membase[memx]+offset); ”呢?
1),已經說過mallco_dev.membase[memx]是首個變量的地址即40k字節中首個字節的地址值;
2),“offset”是:向memx存儲器申請size個字節的連續空閑存儲空間,這個找到的連續空閑空間當中首個字節的地址偏移值就是offset,offset==32(將32個字節空間組成一個內存塊)*內存塊號(如,假設向內部存儲器申請64個字節的連續空閑存儲空間,通過“mem_malloc(memx,size); ”函數得到在第五個存儲塊開始有連續2個存儲快空閑可供使用(假設是5號和4號存儲快),因為每個存儲快有32個字節即有32個地址編號,4*32==128(這里的4是指第四塊),5*32==160(這里的5是指第五塊),那么這個160就是40K個字節編號當中的地址偏移值offset,即128-192號就是第四塊和第五塊內存塊所對應的指針編號);注意offset是地址偏移值而不是地址;為什么要引入地址偏移值這個概念呢?假設第一個字節的地址值是0x0000 6800,那么就知道(0x0000 6800+160)的值就是第五塊內存的指針。
3),“(u32)mallco_dev.membase[memx]”代表指針類型數組,意義是內部存儲器40K字節中的第一個字節變量的地址,原來存放的是u8類型數據的地址,現在強制類型轉換擴展為u32類型;
4),(void*)((u32)mallco_dev.membase[memx]+offset); 轉換為無類型指針,指針值是32位,由此可知,“void *mymalloc(u8 memx,u32 size)”函數的返回值就是一個指針,即形參size所指向的由高向低的首個指針值;“void *mymalloc(u8 memx,u32 size)”是個指針類型函數,只能賦給指針。
*/
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:要分配的內存大小(字節)
//返回值:新分配到的內存首地址.
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個字節指針ptr復制到“((u32)mallco_dev.membase[memx]+offset)”,
myfree(memx,ptr); //釋放舊內存,因為在mem_malloc(memx,size)中已經將連續空閑內存塊標注為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內存參數設定.mem1完全處于內部SRAM里面
#define MEM1_BLOCK_SIZE 32 //內存塊大小為32字節
#define MEM1_MAX_SIZE 40*1024 //最大管理內存 40K
#define MEM1_ALLOC_TABLE_SIZE MEM1_MAX_SIZE/MEM1_BLOCK_SIZE //內存表大小
//mem2內存參數設定.mem2的內存池處于外部SRAM里面,其他的處于內部SRAM里面
#define MEM2_BLOCK_SIZE 32 //內存塊大小為32字節
#define MEM2_MAX_SIZE 200*1024 //最大管理內存200K
主站蜘蛛池模板:
乳山市|
夏河县|
四会市|
双流县|
和政县|
海兴县|
木里|
江达县|
汝城县|
卓资县|
青州市|
凤翔县|
穆棱市|
织金县|
墨江|
乌拉特前旗|
玛多县|
盐城市|
土默特右旗|
镇宁|
屯留县|
肇东市|
延寿县|
长治县|
抚顺县|
光泽县|
蒙城县|
察哈|
海南省|
垣曲县|
成都市|
南昌县|
岫岩|
龙口市|
那曲县|
托克托县|
罗山县|
海淀区|
日照市|
荔浦县|
镇巴县|
評論