久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

專注電子技術(shù)學(xué)習(xí)與研究
當(dāng)前位置:單片機(jī)教程網(wǎng) >> MCU設(shè)計(jì)實(shí)例 >> 瀏覽文章

基于stm32f103zet6的內(nèi)存管理的學(xué)習(xí)

作者:王衍   來源:本站原創(chuàng)   點(diǎn)擊數(shù):  更新時(shí)間:2014年03月11日   【字體:

主要是依照原子哥哥的代碼來初步了解或者說學(xué)習(xí)一下內(nèi)存管理,特別對于我們這個(gè)想往嵌入式方向發(fā)展的人來說,內(nèi)存管理應(yīng)該是一種藝術(shù)的。

今天在對原子的代碼稍作修改是可以進(jìn)行內(nèi)存分配和回收的,所以開始深入分析一下這個(gè)代碼的實(shí)現(xiàn)過程。一、所謂的內(nèi)存管理內(nèi)存管理,是指軟件運(yùn)行時(shí)對計(jì)算機(jī)內(nèi)存資源的分配和使用的技術(shù)。其最主要的目的是如何高效,快速的分配,并且在適當(dāng)?shù)臅r(shí)候釋放和回收內(nèi)存資源。

二、代碼分析

1、首先了解一下一個(gè)數(shù)據(jù)結(jié)構(gòu),這是一個(gè)聲明

 

/*************************** 內(nèi)存管理控制 **********************************************/ typedef struct {void (*init)(u8);//初始化u8 (*perused)(u8); //內(nèi)存使用率u8 *membase[2];//內(nèi)存池 管理2個(gè)區(qū)域的內(nèi)存u16 *memmap[2]; //內(nèi)存管理狀態(tài)表u8 memrdy[2]; //內(nèi)存管理是否就緒}_m_mallco_dev;

 

成員包括兩個(gè)函數(shù)指針(該指針指向函數(shù)),兩個(gè)指針數(shù)組和一個(gè)u8類型的數(shù)組,具體分析下這幾個(gè)成員的含義,那么首先要找到這個(gè)

 

_m_mallco_dev mallco_dev={mem_init,//內(nèi)存初始化mem_perused,//內(nèi)存使用率mem1base,mem2base,//內(nèi)存池 mem1mapbase,mem2mapbase,//內(nèi)存管理狀態(tài)表0,0, //內(nèi)存管理未就緒};這才是真正定義的地方,現(xiàn)在就可以了解這個(gè)幾個(gè)成員的具體功能了。

 

a、初始化中 mem_init,mem_perused,這是兩個(gè)函數(shù),為什么可以這樣用呢(直接用函數(shù)名)?

 可以這樣理解么,函數(shù)名就像數(shù)組名一樣,只不過函數(shù)名是代碼段的指針,而數(shù)組名是數(shù)據(jù)段的指針 ,所以這里函數(shù)名就是給函數(shù)指針賦值了。當(dāng)然函數(shù)指針并不能說是等于指針的,就像數(shù)組一樣,數(shù)組名不等于指針的。總書記和主席還是不一樣的。所以暫時(shí)可以這樣理解,函數(shù)名雖然代表了一個(gè)地址,但是這個(gè)值是確定了的,但是指針是可以指向別的地址的。就這樣!這樣寫只不過是為了方便我們訪問罷了。可以按自己的需要修改!
那么這兩個(gè)函數(shù)的作用?這才是我們最關(guān)心的,看這個(gè)
void mem_init(u8 memx) { mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);//內(nèi)存狀態(tài)表數(shù)據(jù)清零 mymemset(mallco_dev.membase[memx], 0,memsize[memx]);//內(nèi)存池所有數(shù)據(jù)清零 mallco_dev.memrdy[memx]=1;//內(nèi)存管理初始化OK } b、注釋很明確,那么接下來就是分析這個(gè)三句話的作用,沒辦法,我無法做到,一眼能看出究竟。
mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);等價(jià)于mymemset(mem1base, 0,0x500*2)
它里面的內(nèi)容很簡單就是
void mymemset(void *s,u8 c,u32 count) { u8 *xs = s; while(count--)*xs++=c; }以mem1base為首地址的大小為0xa00的內(nèi)容清0,那么mem1base又是什么呢?接下來看看
__align(4) u8 mem1base[MEM1_MAX_SIZE];這明顯是4字節(jié)對齊的內(nèi)部SRAM的地址,也就是我們的flash里面的地址。所以這就實(shí)現(xiàn)了對我們內(nèi)部flash0xa00的內(nèi)容清零,好的繼續(xù)看下面的
 
c、 mymemset(mallco_dev.membase[memx], 0,memsize[memx]); //內(nèi)存池所有數(shù)據(jù)清零  
 
自然地這個(gè)也是一個(gè)意思,清零,唯一不同的就是代表的意思不一樣,到底是內(nèi)存池?cái)?shù)據(jù)清零,還是狀態(tài)表的清零,我們看不出來,那么只有繼續(xù)分析了。清零完成就給相應(yīng)的數(shù)組元素填充1表示完成標(biāo)志。至此我們第一個(gè)初始化成員就分析完畢!!
2、下面開始分析第二個(gè)成員perused函數(shù)
先看函數(shù)如何定義的/***************************************************************************************
名 稱: mem_perused
* 功 能: 獲取內(nèi)存使用率
* 參 數(shù): *memx:所屬內(nèi)存塊
* 返 回 值: 使用率(0~100)**************************************************************************************
/u8 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]);
} 這里可以看到出現(xiàn)一個(gè)這樣的表達(dá)式,需要仔細(xì)分析!mallco_dev.memmap[memx][i]
分解一下,還是一樣,這個(gè)是指針數(shù)組,也就是數(shù)組里面存放的是指針,那么這里給它賦值為一個(gè)數(shù)組名 mem1mapbase,但是訪問的時(shí)候還是可以用下表來訪問的。那么可以替換為:if(mem1mapbase[i]) used++;看到?jīng)],這還是我們之前訪問過了的那個(gè)數(shù)組,只不過這里是當(dāng)非零的時(shí)候執(zhí)行used++,也就是我們占用了才會(huì)進(jìn)行++。那么作用就是:used表示的是占用了的大小。(used*100)/(memtblsize[memx])表示的就是占用值,memtblsize[memx]使我們分配的總的大小,到這里那么第二個(gè)成員也分析完畢。
3、后面這幾個(gè)成員變量,之前就已經(jīng)分析過了。mem1base,mem2base,//內(nèi)存池mem1mapbase,mem2mapbase,//內(nèi)存管理狀態(tài)表0,0, 這里就不詳述了。這個(gè)數(shù)據(jù)結(jié)果分析至此,那么接下來看我們分配內(nèi)存的過程究竟如何實(shí)現(xiàn)?
三、分配內(nèi)存
首先看一個(gè)核心代碼如下

 

/***************************************************************************************
名 稱: mem_malloc
* 功 能: 內(nèi)存分配(內(nèi)部調(diào)用)
* 參 數(shù): *memx:所屬內(nèi)存塊*size:要分配的內(nèi)存大小(字節(jié))
* 返 回 值: 0XFFFFFFFF,代表錯(cuò)誤;其他,內(nèi)存偏移地址
**************************************************************************************
u32 mem_malloc(u8 memx,u32 size)
{
      signed long offset=0;
     u16 nmemb;//需要的內(nèi)存塊數(shù)
     u16 cmemb=0;//連續(xù)空內(nèi)存塊數(shù)
     u32 i;
     if(!mallco_dev.memrdy[memx])mallco_dev.init(memx);//未初始化,先執(zhí)行初始化
     if(size==0)return 0XFFFFFFFF;//不需要分配
     nmemb=size/memblksize[memx]; //獲取需要分配的連續(xù)內(nèi)存塊數(shù)
     if(size%memblksize[memx])nmemb++;
     for(offset=memtblsize[memx]-1;offset>=0;offset--) //搜索整個(gè)內(nèi)存控制區(qū)
     {
         if(!mallco_dev.memmap[memx][offset])cmemb++; //連續(xù)空內(nèi)存塊數(shù)增加
         else cmemb=0; //連續(xù)內(nèi)存塊清零
        if(cmemb==nmemb) //找到了連續(xù)nmemb個(gè)空內(nèi)存塊
           {
                  for(i=0;i<nmemb;i++) //標(biāo)注內(nèi)存塊非空
                     {
                          mallco_dev.memmap[memx][offset+i]=nmemb;
                    }
                 return   (offset*memblksize[memx]);//返回偏移地址 }
          }
       return     0XFFFFFFFF;//未找到符合分配條件的內(nèi)存塊
}

1、首先進(jìn)行的是一個(gè)初始化,初始化的作用上面已經(jīng)提及,再次不贅述,這里我們假設(shè)一塊內(nèi)存為40個(gè)block(一個(gè)block為32字節(jié),因?yàn)閮?nèi)存太小)那么接下來可以看到是通過我們傳入的參數(shù)計(jì)算出了總的內(nèi)存塊數(shù),并且如果不整除的話,還會(huì)多分配一個(gè)內(nèi)存塊。nmemb = 64。內(nèi)存管理表內(nèi)容用于檢測該塊是否被占用。注意這里的內(nèi)存塊一定是連續(xù)的,

內(nèi)存管理表的項(xiàng)值代表的意義為:當(dāng)該項(xiàng)值為0的時(shí)候,代表對應(yīng)的內(nèi)存塊未被占用,當(dāng)該項(xiàng)值非零的時(shí)候,代表該項(xiàng)對應(yīng)的內(nèi)存塊已經(jīng)被占用,其數(shù)值則代表被連續(xù)占用的內(nèi)存塊數(shù)。比如某項(xiàng)值為10,那么說明包括本項(xiàng)對應(yīng)的內(nèi)存塊在內(nèi),總共分配了10個(gè)內(nèi)存塊給外部的某個(gè)指針。
 

之后就是標(biāo)志代碼了,注釋很詳細(xì),接下來看看這個(gè)返回偏移地址的代碼:offset*memblksize[memx],這個(gè)偏移值就是memblksize【0】 = 0x20*offset

2、好的,接下來就是將偏移值轉(zhuǎn)化為所謂的外部指針了。

 

else return (void*)((u32)mallco_dev.membase[memx]+offset);
這行代碼,返回一個(gè)void 類型的首地址就是mallco_dev.membase[0],這樣我們就得到了一個(gè)地址了。

 

3、然后就是

 

p=mymalloc(sramx,2048); //申請2K字節(jié)if(p!=NULL)sprintf((char*)p,"This is xiaobing's Memory Malloc Test!!");//向p寫入一些內(nèi)容 printf("%s",p); //顯示P的內(nèi)容

 

這就是把這個(gè)地址傳給指針p,那么我們接著就可以給指針p賦值內(nèi)容了,這回爽到了吧?

打印指針內(nèi)容。

4、很重要的一步

myfree(sramx,p);//釋放內(nèi)存,否則資源難以回收
 

記得要釋放內(nèi)存呀,看代碼函數(shù)

 

/*************************************************************************************** 名 稱: mem_free* 功 能: 釋放內(nèi)存(內(nèi)部調(diào)用)* 參 數(shù): *memx:所屬內(nèi)存塊* offset:內(nèi)存地址偏移* 返 回 值: 0,釋放成功;1,釋放失敗; **************************************************************************************/u8 mem_free(u8 memx,u32 offset) { int i; if(!mallco_dev.memrdy[memx])//未初始化,先執(zhí)行初始化{mallco_dev.init(memx); return 1;//未初始化 } if(offset<memsize[memx])//偏移在內(nèi)存池內(nèi). { int index=offset/memblksize[memx];//偏移所在內(nèi)存塊號碼 int nmemb=mallco_dev.memmap[memx][index];//內(nèi)存塊數(shù)量 for(i=0;i<nmemb;i++) //內(nèi)存塊清零 { mallco_dev.memmap[memx][index+i]=0; } return 0; }else return 2;//偏移超區(qū)了. } 就是將內(nèi)存塊清零,與之前的那行代碼對應(yīng)就是

 

 

mallco_dev.memmap[memx][offset+i]=nmemb;標(biāo)注非空了,那么也就是說,我們占用了的那些內(nèi)存塊就會(huì)標(biāo)記為nmenb,否則就是0。

 

當(dāng)我們釋放完內(nèi)存后,記得加上這個(gè)  P = NULL.

只是為了防止產(chǎn)生野指針,誰能保證,每次運(yùn)行程序的時(shí)候,給變量分配地址的時(shí)候,不會(huì)使用到這個(gè)地址呢??所以這是個(gè)好習(xí)慣!

關(guān)閉窗口

相關(guān)文章

主站蜘蛛池模板: 久久婷婷av| 在线免费观看色 | 久久这里只有精品首页 | 日韩快播电影网 | h视频在线播放 | 国产在线播放一区二区三区 | 日韩一级免费大片 | 6996成人影院网在线播放 | 国产精品美女久久久久aⅴ国产馆 | 99久久99热这里只有精品 | 亚洲午夜网 | 在线黄av| 日韩视频在线一区 | 欧美成人a∨高清免费观看 91伊人 | 亚洲一区视频在线 | 欧美二区三区 | 最新国产在线 | 亚洲精品一区二区二区 | 亚洲一区二区三区免费在线观看 | 亚洲一区二区在线视频 | 色一阁| 91精品国产综合久久久久久漫画 | 亚洲欧洲视频 | 国产在线网站 | 国产成人精品久久二区二区91 | 国产精品特级毛片一区二区三区 | 国产精品无码久久久久 | 台湾佬久久 | 免费国产精品久久久久久 | 中文久久 | 特黄av| 日本激情视频中文字幕 | 亚洲三级在线观看 | av入口 | 伊人久操| 精品一区二区电影 | 精品国产一区二区三区久久狼黑人 | 亚洲va中文字幕 | 精品欧美一区二区在线观看欧美熟 | 亚洲精品视频免费 | 99热这里有精品 |