<acronym id="xonnx"></acronym>
      <td id="xonnx"></td>
    1. <pre id="xonnx"></pre>

      1. 專注電子技術學習與研究
        當前位置:單片機教程網 >> MCU設計實例 >> 瀏覽文章

        基于stm32f103zet6的內存管理的學習

        作者:王衍   來源:本站原創   點擊數:  更新時間:2014年03月11日   【字體:

        主要是依照原子哥哥的代碼來初步了解或者說學習一下內存管理,特別對于我們這個想往嵌入式方向發展的人來說,內存管理應該是一種藝術的。

        今天在對原子的代碼稍作修改是可以進行內存分配和回收的,所以開始深入分析一下這個代碼的實現過程。一、所謂的內存管理內存管理,是指軟件運行時對計算機內存資源的分配和使用的技術。其最主要的目的是如何高效,快速的分配,并且在適當的時候釋放和回收內存資源。

        二、代碼分析

        1、首先了解一下一個數據結構,這是一個聲明

         

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

         

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

         

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

         

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

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

         

        /***************************************************************************************
        名 稱: mem_malloc
        * 功 能: 內存分配(內部調用)
        * 參 數: *memx:所屬內存塊*size:要分配的內存大小(字節)
        * 返 回 值: 0XFFFFFFFF,代表錯誤;其他,內存偏移地址
        **************************************************************************************
        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);//未初始化,先執行初始化
             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;//未找到符合分配條件的內存塊
        }

        1、首先進行的是一個初始化,初始化的作用上面已經提及,再次不贅述,這里我們假設一塊內存為40個block(一個block為32字節,因為內存太。┠敲唇酉聛砜梢钥吹绞峭ㄟ^我們傳入的參數計算出了總的內存塊數,并且如果不整除的話,還會多分配一個內存塊。nmemb = 64。內存管理表內容用于檢測該塊是否被占用。注意這里的內存塊一定是連續的,

        內存管理表的項值代表的意義為:當該項值為0的時候,代表對應的內存塊未被占用,當該項值非零的時候,代表該項對應的內存塊已經被占用,其數值則代表被連續占用的內存塊數。比如某項值為10,那么說明包括本項對應的內存塊在內,總共分配了10個內存塊給外部的某個指針。
         

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

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

         

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

         

        3、然后就是

         

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

         

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

        打印指針內容。

        4、很重要的一步

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

        記得要釋放內存呀,看代碼函數

         

        /*************************************************************************************** 名 稱: mem_free* 功 能: 釋放內存(內部調用)* 參 數: *memx:所屬內存塊* offset:內存地址偏移* 返 回 值: 0,釋放成功;1,釋放失敗; **************************************************************************************/u8 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;//偏移超區了. } 就是將內存塊清零,與之前的那行代碼對應就是

         

         

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

         

        當我們釋放完內存后,記得加上這個  P = NULL.

        只是為了防止產生野指針,誰能保證,每次運行程序的時候,給變量分配地址的時候,不會使用到這個地址呢??所以這是個好習慣!

        關閉窗口

        相關文章

        欧美性色欧美精品视频,99热这里只有精品mp4,日韩高清亚洲日韩精品一区二区,2020国自产拍精品高潮