<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 元件/連接器 > 設(shè)計應(yīng)用 > Keil C動態(tài)內(nèi)存管理機制分析及改進

          Keil C動態(tài)內(nèi)存管理機制分析及改進

          ——
          作者:重慶電力高等??茖W校 丁明亮 熊真春 時間:2007-07-04 來源:單片機及嵌入式系統(tǒng)應(yīng)用 收藏
           Keil C是常用的嵌入式系統(tǒng)編程工具,它通過init_mempool、mallloe、free等函數(shù),提供了動態(tài)存儲管理等功能。本文通過對init_mempool、mallloe和free這3個KeilC庫函數(shù)源代碼的分析,揭示其實現(xiàn)的原理和方法,并對其中的不足作了改進,以使Keil C編程人員更好地應(yīng)用動態(tài)存儲管理。

            1 相關(guān)數(shù)據(jù)結(jié)構(gòu)、變量及說明

            在Keil C安裝目錄下的\c5l\lib目錄下,有實現(xiàn)init_mempool、mallloe和free這3個函數(shù)的C源文件init_mere.c、malloc.e和free.c。下面針對keil C7.5A版,將其中與動態(tài)存儲管理相關(guān)的數(shù)據(jù)結(jié)構(gòu)介紹如下:

          與動態(tài)存儲管理相關(guān)的數(shù)據(jù)結(jié)構(gòu)

            該結(jié)構(gòu)的next指向堆中的下一空閑內(nèi)存塊,len表示該空閑塊除去該塊首部的struct__mem__結(jié)構(gòu)所占的字節(jié)數(shù)后,該塊實際可用的字節(jié)數(shù)。由于next是一個指向XDATA區(qū)的指針,故在Keil C中應(yīng)用程序所定義的堆空間應(yīng)在XDATA段中定義。

            在Keil C中,堆中的所有空閑內(nèi)存塊是用一個單鏈表來管理的,struct_mere_即為該鏈表結(jié)點的結(jié)構(gòu),后面定義的宏AVAIL為該鏈表的首結(jié)點,為敘述方便,以下將該鏈表稱為AVAIL鏈表。

          AVAIL鏈表

            #define AVAIL(__meM_avaiL_[O])

            全局數(shù)組__meM_ avail_實際也是struct__mem__類型,__mem_avail__[O]的next指向堆中首塊空閑塊。如果堆中已無空閑內(nèi)存塊,則__mem_avail__[0]的next為NULL(0值)。為使程序代碼簡潔,定義了宏AVAIL來代替__mem_avail__[O]。

            2 init_mempool函數(shù)剖析

            函數(shù)int_mempool(void_MALLOC_MEM_*pool,unsigned int size)失敗時將返回0,成功則返回一1,參數(shù)pool指向應(yīng)用程序定義的堆空間,參數(shù)size為堆空間的字節(jié)數(shù)。如果應(yīng)用程序提供的堆空間太小(size的值太小),將失去實際意義,故函數(shù)將返回0表示失敗。當size參數(shù)足夠大,則會初始化AVAIL(即_mem_avail__[O]),使其next域指向pool參數(shù)所指向的堆空間,len域為pool參數(shù)所指向的堆空間的總字節(jié)數(shù)size。其在KeilC 7.5A庫中init_mem.C的源代碼如下:

          C的源代碼

            在成功執(zhí)行init_mempool函數(shù)后,將得到如圖1所示的一個數(shù)據(jù)結(jié)構(gòu)。另外,鏈首結(jié)點AVAIL的len域記錄了整個堆的字節(jié)數(shù)。鏈首AVAIL結(jié)點的next域指向的是首塊空閑塊,當經(jīng)過多次的malloe函數(shù)而堆中投有空閑內(nèi)存塊時,AVAIL結(jié)點的next域?qū)镹ULL值。

          數(shù)據(jù)結(jié)構(gòu)

            很明顯,從上面的if(pool==NULL){pool=1;size--;)這部分源代碼來看,如果應(yīng)用程序中pool參數(shù)為空指針(pool為0)

           
          時,顯然不能直接將AVAIL,的next域的值賦為空指針的(即賦為O)。將pool的值改為1,再將size的值減l,這樣,init_mempool函數(shù)會在XDATA區(qū)中,從地址l開始,取size一1個字節(jié)作為堆來使用。如果源程序有定義在XDATA區(qū)的變量,則這些變量所占的存儲單元也可能會被當成堆空間的一部分,這無疑是有潛在風險的。

            部分程序員在調(diào)用init_mempool函數(shù)時,習慣將pool參數(shù)設(shè)為一個形如0xAAAA數(shù)字表示的絕對地址,如果不加特別防范,也是不妥的,因為Keil C可能會在此方式指定的堆空間中分配臨時變量。好的習慣是定義一個字節(jié)數(shù)組作為堆空間,再將數(shù)組名作為pool參數(shù)調(diào)用init_mempool函數(shù)。

            在Keil C的聯(lián)機文檔中,指明了init_mempool在應(yīng)用程序中只能被調(diào)用一次,那么,如果多次調(diào)用該函數(shù)又會有什么后果呢?從該函數(shù)的源代碼來分析,多次調(diào)用init_mempoo1函數(shù),會導致重新初始化首結(jié)點AVAIL的next域和len域的值,將使AVAIL鏈表中的原有管理信息丟失,從而導致一些很難診斷的問題。

            對此問題,可采用如下保護措施。當發(fā)現(xiàn)AVAIL鏈表中已有管理信息時,則返回失敗標志,函數(shù)直接返回。具體的方法是檢查AVAIL結(jié)點的len域,由于其被初始化為零,如果發(fā)現(xiàn)其值非零,則表明init_mempool函數(shù)已被成功調(diào)用過,此時函數(shù)直接返回。

           Keil C是常用的嵌入式系統(tǒng)編程工具,它通過init_mempool、mallloe、free等函數(shù),提供了動態(tài)存儲管理等功能。本文通過對init_mempool、mallloe和free這3個KeilC庫函數(shù)源代碼的分析,揭示其實現(xiàn)的原理和方法,并對其中的不足作了改進,以使Keil C編程人員更好地應(yīng)用動態(tài)存儲管理。

            1 相關(guān)數(shù)據(jù)結(jié)構(gòu)、變量及說明

            在Keil C安裝目錄下的\c5l\lib目錄下,有實現(xiàn)init_mempool、mallloe和free這3個函數(shù)的C源文件init_mere.c、malloc.e和free.c。下面針對keil C7.5A版,將其中與動態(tài)存儲管理相關(guān)的數(shù)據(jù)結(jié)構(gòu)介紹如下:

          與動態(tài)存儲管理相關(guān)的數(shù)據(jù)結(jié)構(gòu)

            該結(jié)構(gòu)的next指向堆中的下一空閑內(nèi)存塊,len表示該空閑塊除去該塊首部的struct__mem__結(jié)構(gòu)所占的字節(jié)數(shù)后,該塊實際可用的字節(jié)數(shù)。由于next是一個指向XDATA區(qū)的指針,故在Keil C中應(yīng)用程序所定義的堆空間應(yīng)在XDATA段中定義。

            在Keil C中,堆中的所有空閑內(nèi)存塊是用一個單鏈表來管理的,struct_mere_即為該鏈表結(jié)點的結(jié)構(gòu),后面定義的宏AVAIL為該鏈表的首結(jié)點,為敘述方便,以下將該鏈表稱為AVAIL鏈表。

          AVAIL鏈表

            #define AVAIL(__meM_avaiL_[O])

            全局數(shù)組__meM_ avail_實際也是struct__mem__類型,__mem_avail__[O]的next指向堆中首塊空閑塊。如果堆中已無空閑內(nèi)存塊,則__mem_avail__[0]的next為NULL(0值)。為使程序代碼簡潔,定義了宏AVAIL來代替__mem_avail__[O]。

            2 init_mempool函數(shù)剖析

            函數(shù)int_mempool(void_MALLOC_MEM_*pool,unsigned int size)失敗時將返回0,成功則返回一1,參數(shù)pool指向應(yīng)用程序定義的堆空間,參數(shù)size為堆空間的字節(jié)數(shù)。如果應(yīng)用程序提供的堆空間太小(size的值太小),將失去實際意義,故函數(shù)將返回0表示失敗。當size參數(shù)足夠大,則會初始化AVAIL(即_mem_avail__[O]),使其next域指向pool參數(shù)所指向的堆空間,len域為pool參數(shù)所指向的堆空間的總字節(jié)數(shù)size。其在KeilC 7.5A庫中init_mem.C的源代碼如下:

          C的源代碼

            在成功執(zhí)行init_mempool函數(shù)后,將得到如圖1所示的一個數(shù)據(jù)結(jié)構(gòu)。另外,鏈首結(jié)點AVAIL的len域記錄了整個堆的字節(jié)數(shù)。鏈首AVAIL結(jié)點的next域指向的是首塊空閑塊,當經(jīng)過多次的malloe函數(shù)而堆中投有空閑內(nèi)存塊時,AVAIL結(jié)點的next域?qū)镹ULL值。

          數(shù)據(jù)結(jié)構(gòu)

            很明顯,從上面的if(pool==NULL){pool=1;size--;)這部分源代碼來看,如果應(yīng)用程序中pool參數(shù)為空指針(pool為0)

           
          時,顯然不能直接將AVAIL,的next域的值賦為空指針的(即賦為O)。將pool的值改為1,再將size的值減l,這樣,init_mempool函數(shù)會在XDATA區(qū)中,從地址l開始,取size一1個字節(jié)作為堆來使用。如果源程序有定義在XDATA區(qū)的變量,則這些變量所占的存儲單元也可能會被當成堆空間的一部分,這無疑是有潛在風險的。

            部分程序員在調(diào)用init_mempool函數(shù)時,習慣將pool參數(shù)設(shè)為一個形如0xAAAA數(shù)字表示的絕對地址,如果不加特別防范,也是不妥的,因為Keil C可能會在此方式指定的堆空間中分配臨時變量。好的習慣是定義一個字節(jié)數(shù)組作為堆空間,再將數(shù)組名作為pool參數(shù)調(diào)用init_mempool函數(shù)。

            在Keil C的聯(lián)機文檔中,指明了init_mempool在應(yīng)用程序中只能被調(diào)用一次,那么,如果多次調(diào)用該函數(shù)又會有什么后果呢?從該函數(shù)的源代碼來分析,多次調(diào)用init_mempoo1函數(shù),會導致重新初始化首結(jié)點AVAIL的next域和len域的值,將使AVAIL鏈表中的原有管理信息丟失,從而導致一些很難診斷的問題。

            對此問題,可采用如下保護措施。當發(fā)現(xiàn)AVAIL鏈表中已有管理信息時,則返回失敗標志,函數(shù)直接返回。具體的方法是檢查AVAIL結(jié)點的len域,由于其被初始化為零,如果發(fā)現(xiàn)其值非零,則表明init_mempool函數(shù)已被成功調(diào)用過,此時函數(shù)直接返回。



          關(guān)鍵詞: 存儲器

          評論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();