新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 基于STM32原子戰艦板內存管理源碼

        基于STM32原子戰艦板內存管理源碼

        作者: 時間:2016-12-01 來源:網絡 收藏
        */
        //復制內存,作用是將源地址的內容復制到目標地址
        //*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
        #define MEM2_ALLOC_TABLE_SIZE MEM2_MAX_SIZE/MEM2_BLOCK_SIZE //內存表大小

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 乳山市| 夏河县| 四会市| 双流县| 和政县| 海兴县| 木里| 江达县| 汝城县| 卓资县| 青州市| 凤翔县| 穆棱市| 织金县| 墨江| 乌拉特前旗| 玛多县| 盐城市| 土默特右旗| 镇宁| 屯留县| 肇东市| 延寿县| 长治县| 抚顺县| 光泽县| 蒙城县| 察哈| 海南省| 垣曲县| 成都市| 南昌县| 岫岩| 龙口市| 那曲县| 托克托县| 罗山县| 海淀区| 日照市| 荔浦县| 镇巴县|