Keil C動態(tài)內存管理機制分析及改進_第1頁
Keil C動態(tài)內存管理機制分析及改進_第2頁
Keil C動態(tài)內存管理機制分析及改進_第3頁
全文預覽已結束

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、Keil C動態(tài)內存管理機制分析及改進Keil C是常用的嵌入式系統(tǒng)編程工具,它通過init_mempool、mallloe、free等函數(shù),提供了動態(tài)存儲管理等功能。本文通過 對init_mempool、mallloe和free這3個KeilC庫函數(shù)源代碼的分析,揭示其實現(xiàn)的原理和方法,并對其中的不足作了改進,以 使Keil C編程人員更好地應用動態(tài)存儲管理。1相關數(shù)據(jù)結構、變量及說明在Keil C安裝目錄下的c5l lib目錄下,有實現(xiàn)init_mempool、mallloe和free這3個函數(shù)的C源文件init_mere. c、malloc. e 和free. c。下面針對keil C7

2、. 5A版,將其中與動態(tài)存儲管理相關的數(shù)據(jù)結構介紹如下;片 define _MALLOC.MEM_xdata / * 該行在 stdlib. h 文件中法 /struct _mem_ struct _memMALLOC_MEM_ * next / * 單鏈表 * /unsigned int lenj/嫌 下一塊長度 關/h該結構的next指向堆中的下一空閑內存塊,len表示該空閑塊除去該塊首部的struct_mem結構所占的字節(jié)數(shù)后,該塊實際 可用的字節(jié)數(shù)。由于next是一個指向XDATA區(qū)的指針,故在Keil C中應用程序所定義的堆空間應在XDATA段中定義。在Keil C中,堆中的所有空閑

3、內存塊是用一個單鏈表來管理的,struct_mere_即為該鏈表結點的結構,后面定義的宏AVAIL 為該鏈表的首結點,為敘述方便,以下將該鏈表稱為AVAIL鏈表。typedef struct_mem_memt_;typedef _memtMALLOC_MEM_ * _memp_ ;_memtMALLOC_MEMmem_avail_ 2: = NULL, 0 ,/決堆中空閑內存塊頭結點* / NULL, 0 ,/*未使用,但對free函數(shù)防止丟失堆空間或誤將鏈表頭加入到堆空間,卻是必須的*/ *筆者注:_mcm_avail_ 1的存在并不能防止堆丟失,見后面fr哉函數(shù)分析* /打#define

4、AVAIL(_meM_avaiLO)全局數(shù)組meM_ avail_實際也是struct_mem類型,mem_avail_O的next指向堆中首塊空閑塊。如果堆中已無空閑 內存塊,則mem_avail_0的next為NULL(O值)。為使程序代碼簡潔,定義了宏AVAIL來代替_mem_availO。2 init_mempool 函數(shù)剖析函數(shù) int_mempool(void_MALLOC_MEM_* pool,unsigned int size)失敗時將返回0,成功則返回一 1參數(shù)pool指向應用程序定義的堆空間,參數(shù)size為堆空間的字節(jié)數(shù)。 如果應用程序提供的堆空間太小(size的值太小),

5、將失去實際意義,故函數(shù)將返回0表示失敗。當size參數(shù)足夠大,則會初始化 AVAIL(即_mem_avail_O),使其next域指向pool參數(shù)所指向的堆空間,len域為pool參數(shù)所指向的堆空間的總字節(jié)數(shù)size。 其在KeilC 7. 5A庫中init_mem. C的源代碼如下: # define HLEN (sizeof(_memt_)4 define MIN_POOL_SIZE (HLEN * 10)int init_mempool (void _MALLCX2_MEM_ * pool, unsigned int size) if (size next = NULL?(AVAIL,

6、next) len = size HLEN; return ( 1) ;/ * 成功 * /在成功執(zhí)行init_mempool函數(shù)后,將得到如圖1所示的一個數(shù)據(jù)結構。另外,鏈首結點AVAIL的len域記錄了整個堆的字節(jié) 數(shù)。鏈首AVAIL結點的next域指向的是首塊空閑塊,當經過多次的malloe函數(shù)而堆中投有空閑內存塊時,AVAIL結點的next 域將為NULL值。圖1 init_mempool執(zhí)行后的AVAIL鏈表及堆空間很明顯,從上面的if(pool=NULL)pool=1 ; size-;)這部分源代碼來看,如果應用程序中pool參數(shù)為空指針(pool為0)時, 顯然不能直接將AVAI

7、L,的next域的值賦為空指針的(即賦為O)。將pool的值改為1,再將size的值減I,這樣,init_mempool 函數(shù)會在XDATA區(qū)中,從地址l開始,取size 一 1個字節(jié)作為堆來使用。如果源程序有定義在XDATA區(qū)的變量,則這些變量 所占的存儲單元也可能會被當成堆空間的一部分,這無疑是有潛在風險的。部分程序員在調用init_mempool函數(shù)時,習慣將pool參數(shù)設為一個形如0 xAAAA數(shù)字表示的絕對地址,如果不加特別防范, 也是不妥的,因為Keil C可能會在此方式指定的堆空間中分配臨時變量。好的習慣是定義一個字節(jié)數(shù)組作為堆空間,再將數(shù)組名 作為 pool參數(shù)調用init_m

8、empool函數(shù)。在Keil C的聯(lián)機文檔中,指明了 init_mempool在應用程序中只能被調用一次,那么,如果多次調用該函數(shù)又會有什么后果呢? 從該函數(shù)的源代碼來分析,多次調用init_mempoo1函數(shù),會導致重新初始化首結點AVAIL的next域和len域的值,將使AVAIL 鏈表中的原有管理信息丟失,從而導致一些很難診斷的問題。對此問題,可采用如下保護措施。當發(fā)現(xiàn)AVAIL鏈表中已有管理信息時,則返回失敗標志,函數(shù)直接返回。具體的方法是檢 查AVAIL結點的len域,由于其被初始化為零,如果發(fā)現(xiàn)其值非零,則表明init_mempool函數(shù)已被成功調用過,此時函數(shù)直接 返回。3 ma

9、lloc函數(shù)分析malloc函數(shù)的原形是void *malloc(unsigned intsize),size參數(shù)為需動態(tài)申請的內存塊的字節(jié)數(shù)。malloc函數(shù)的算法是查找AVAIL鏈表中各結點next指針所指向的空閑內存塊。如果某塊的空閑字節(jié)數(shù)size參數(shù),則停止查找, 并從該塊進行內存分配,返回一個指向所分配內存塊的指針給應用程序。如果沒有找到符合要求的空閑內存塊,則返回空指針給 應用程序。需要注意的是,AVAIL鏈表中除首結點AVAIL外,其余各節(jié)點位于堆中各空閑內存塊開始處的一個struct_mem_結構中, 其len域為該空閑塊總字節(jié)數(shù)減去sizeof(stiuct_mem)后的值,

10、即該塊實際空閑的字節(jié)數(shù);next域指向堆中下一空閑內存塊。設鏈表節(jié)點p指向所找到的空閑內存塊,如果在p空閑塊分配size個字節(jié)后,剩余的字節(jié)數(shù)不多,則將p塊從AVAIL鏈表中 刪除,然后返回一個指向p塊偏移sizeof(struct_mem)處的指針。如果在p空閑塊分配size個字節(jié)后,該塊仍剩余較多的字節(jié) 數(shù),則需對該塊進行分割,將多出的這一部分保留在AVAIL鏈表中。(以下部分有省略,全文請見本刊網站一一編者注)4 free函數(shù)分析及改進free函數(shù)的原形是void free(void xdata *memp),參數(shù)memp指向所要釋放的內存塊。在AVAIL鏈表中,各結點是按其所指空閑內存

11、塊開始地址的大小按升序排列的。free函數(shù)的算法是在AVAIL鏈表中查一個節(jié) 點p(其前驅為q),當p節(jié)點所指空問內存塊的地址大于參數(shù)memp所指內存塊的起始地址時,則將memp塊插入到該節(jié)點之前, 如沒有找到這樣的節(jié)點,則memp塊插到鏈尾。在插入memp塊時,還將檢查在memp塊的前后是否存在地址相鄰的空閑內存 塊,如果有,則將 memp 塊與相鄰塊合并。 (free 庫函數(shù)的部分源代碼見本刊網站一一編者注)值得探討的是最后一段將memp塊與前一塊(q塊)合并的這部分代碼。如果在執(zhí)行此部分代碼之前,q指向首結點AVAIL,而 此時欲將q塊與memp塊合并,顯然是不合理的。實際上,此時應當將q的next指針的值設為memp塊的開始地址pO。由于 KeilC7. 5A中,free庫函數(shù)的源程序中沒有考慮這種特殊情況,因此可能會引發(fā)嚴重后果。由源代碼分析可知,q指向首結點AVAIL,而此時如果滿足。memp塊與q塊合并的判定條件,執(zhí)行q1en+=p0 Len+HL, EN和q next=pO next后,不但不能回收內存,反而導致memp塊丟失;同時,AVAIL的len域的值也不正確。如果此時 pO 一next又為NULL,則會導致整個堆內存的丟失。筆者特在 Keil C7. 5 A 版中設計了一個示例(見本刊網站), 用于引發(fā)該錯誤。 要

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論