




免費預(yù)覽已結(jié)束,剩余1頁可下載查看
下載本文檔
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
2( 6068a ) Keil C 動態(tài)內(nèi)存管理機制分析及改進 P 74全文如下:Keil C 動態(tài)內(nèi)存管理機制分析及改進 丁明亮 熊真春摘要通過對C51中init_mempool, malloc, free三個函數(shù)源代碼的分析,深入分析C51的動態(tài)內(nèi)存管理機制,同時也給出一些使init_mempool函數(shù)更完善和除去free函數(shù)中的一個錯誤的建議。關(guān)鍵詞 C51 動態(tài)內(nèi)存管理 分析Abstract: based on the analysis to sources of function init_mempool, malloc and free, this article probes the dynamic memory management of C51 Library, and gives out some advices to better function init_mempool and to clear a bug of function free.Key words: C51 dynamic memory management 60.前言Keil C是常用的嵌入式系統(tǒng)編程工具,它通過init_mempool,mallloc,free等函數(shù),提供了動態(tài)存儲管理管理等功能。本文希望通過init_mempool,mallloc,free三個Keil C庫函數(shù)源代碼的分析,揭示了其實現(xiàn)的原理和方法,也對其中的不足作了改進,以使Keil C 編程人員更好地應(yīng)用動態(tài)存儲管理。1相關(guān)數(shù)據(jù)結(jié)構(gòu)、變量及說明在Keil C安裝目錄下的 c51lib目錄下,有實現(xiàn)init_mempool,mallloc,free三個函數(shù)的C源文件init_mem.c,malloc.c,free.c,下面針對keil C7.5A版,將其中與動態(tài)存儲管理相關(guān)的數(shù)據(jù)結(jié)構(gòu)介紹如下:#define _MALLOC_MEM_xdata /*該行在stdlib.h文件中*/struct _mem_ struct _mem_ _MALLOC_MEM_ *next; /* 單鏈表 */ unsigned int len; /*下一塊長度 */ ;該結(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 _mem_即為該鏈表結(jié)點的結(jié)構(gòu),后面定義的宏AVAIL為該鏈表的首結(jié)點,為敘述方便,以下將該鏈表稱為AVAIL鏈表。typedef struct_mem_ _memt_;typedef _memt_ _MALLOC_MEM_ *_memp_;_memt_ _MALLOC_MEM_ _mem_avail_ 2 = NULL, 0 ,/*堆中空閑內(nèi)存塊頭結(jié)點 */ NULL, 0 ,/* 未使用,但對free函數(shù)防止丟失堆空間或誤將鏈表頭加入到堆空間,卻是必須的 */ /*作者注:_mem_avail_ 1的存在,并不能防止堆丟失,見后面free函數(shù)分析*/ ;#define AVAIL(_mem_avail_0)全局?jǐn)?shù)組_mem_avail_實際也是struct _mem_類型,_mem_avail_0的next指向堆中首塊空閑塊,如堆中已無空閑內(nèi)存塊,則_mem_avail_0的next為NULL(0值)。為使程序代碼簡潔,定義了宏AVAIL 來代替_mem_avail_0。2 init_mempool函數(shù)剖析函數(shù)int init_mempool ( void _MALLOC_MEM_ *pool, unsigned int size)失敗時將返回0,成功則返回-1,參數(shù)pool 指向應(yīng)用程序定義的堆空間,參數(shù)size為堆空間的字節(jié)數(shù)。如果應(yīng)用程序提供的堆空間太?。╯ize的值太?。瑢⑹嶋H意義,故函數(shù)將返回0表示失敗。當(dāng)size參數(shù)足夠大,則會初如化AVAIL(即_mem_avail_0),使其next域指向pool參數(shù)所指向的堆空間,len域為pool參數(shù)所指向的堆空間的總字節(jié)數(shù)size。其在Keil C 7.5A庫中init_mem.c的源代碼如下所示。#defineHLEN(sizeof(_memt_)#define MIN_POOL_SIZE(HLEN * 10)int init_mempool (void _MALLOC_MEM_ *pool, unsigned int size)if (size next = NULL;(AVAIL.next)-len = size - HLEN;return (-1);/*成功*/堆NULLsize-HLENAVAILpoolsize圖1: init_mempool執(zhí)行后的AVAIL鏈表及堆空間在成功執(zhí)行init_mempool函數(shù)后,將得到如圖1所示的一個數(shù)據(jù)結(jié)構(gòu)。另外,鏈?zhǔn)捉Y(jié)點AVAIL的len域記錄了整個堆的字節(jié)數(shù)。鏈?zhǔn)譇VAIL結(jié)點的next域指向的是首塊空閑塊,當(dāng)經(jīng)過多次的malloc函數(shù)而堆中沒有空閑內(nèi)存塊時,AVAIL結(jié)點的next域?qū)镹ULL值。很明顯,從上面的if (pool = NULL) pool = 1; size-; 這部分源代碼來看,如果應(yīng)用程序中pool參數(shù)為空指針(pool為0)時,此時顯然不能直接將AVAIL的next 域的值賦為空指針的(即賦為0),于是便將pool的值改為1,再將size的值減1,這樣,init_mempool函數(shù)會在XDATA區(qū)中,從地址1開始,取size-1個字節(jié)來作為堆來使用,如果源程序有定義在XDATA區(qū)的變量,則這些變量所占的存儲單元也可能會被當(dāng)成堆空間的一部分,這無疑是有潛在風(fēng)險的。部分程序員在調(diào)用init_mempool函數(shù)時習(xí)慣將pool參數(shù)設(shè)為一個形如0xAAAA數(shù)字表示的絕對地址,如果不加特別防范,也是不妥的,因為Keil C可能會在你以如此方式指定的堆空間中分配臨時變量。好的習(xí)慣是定義一個字節(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_mempool函數(shù)會導(dǎo)致重新初始化首結(jié)點AVAIL的next域和len域的值,將使AVAIL鏈表中的原有的管理信息丟失,從而導(dǎo)致一些很難診斷的問題。對這個問題,可采用如下的保護措施。當(dāng)發(fā)現(xiàn)AVAIL鏈表中已有管理信息時,則返回失敗標(biāo)志,函數(shù)直接返回。具體的方法是檢查AVAIL結(jié)點的len域,由于其被初始化為零,如果發(fā)現(xiàn)其值非零,則表明init_mempool函數(shù)已被成功調(diào)用過,此時函數(shù)直接返回。3malloc函數(shù)分析malloc函數(shù)的原形是void *malloc (unsigned int size);size參數(shù)為需動態(tài)申請的內(nèi)存塊的字節(jié)數(shù)。malloc函數(shù)的算法是查找AVAIL鏈表中各結(jié)點next指針?biāo)赶虻目臻e內(nèi)存塊,如果某塊的空閑的字節(jié)數(shù)=size參數(shù),則停止查找,并從該塊進行內(nèi)存分配,返回一個指向所分配的內(nèi)存塊的指針給應(yīng)用程序,如果沒有找到合符要求的空閑內(nèi)存塊,則返回空指針給應(yīng)用程序。需要注意的是AVAIL鏈表中除首結(jié)點AVAIL外,其余各節(jié)點是位于堆中各空閑內(nèi)存塊開始處的一個struct _mem_結(jié)構(gòu)中,其len域為該空閑塊總字節(jié)數(shù)減去sizeof(struct _mem)后的值,即該塊實際空閑的字節(jié)數(shù);next域指向堆中下一空閑內(nèi)存塊。設(shè)鏈表節(jié)點p指向所找到的空閑內(nèi)存塊,如果在p空閑塊分配size個字節(jié)后,剩余的字節(jié)數(shù)不多,則將p塊從AVAIL鏈表中刪除,然后返回一個指向p塊偏移sizeof(struct _mem)處的指針。如果在p空閑塊分配size個字節(jié)后,該塊仍剩余較多的字節(jié)數(shù),則需對該塊進行分割,將多出的這一部分保留在AVAIL鏈表中。下面是在malloc.c中該函數(shù)的部分源代碼:#define MIN_BLOCK(HLEN * 4)void _MALLOC_MEM_ *malloc ( unsigned int size)/省略k = p-len - size; /* 計算分配后剩余的字節(jié)數(shù) */if (k next = p-next; /*將p塊從AVAIL鏈表中刪除*/ return (&p1);/* 成功,參見后面分析*/ /*分割該塊*/k -= HLEN;p-len = k;q = (_memp_ ) (char _MALLOC_MEM_ *) (&p 1) + k);q-len = size; /*填入所分配塊的大小*/return (&q1); /* 成功,參見下面分析*/在C語言中,數(shù)組名就是一個內(nèi)存地址,也可把一個指針當(dāng)作一個數(shù)組名;同時C語言數(shù)組的下標(biāo)從0開始,在上面的源代碼中,q為struct struct _mem類型的指針,所以&q1的值等于q塊的起始地址+sizeof(struct struct _mem)的值,也就是說malloc通過return(&q1)語句返回給應(yīng)用程序的內(nèi)存塊指針,實際是指向所分配內(nèi)存塊偏移sizeof(struct struct _mem_)處的。假設(shè)我們的應(yīng)用程序中有一指向某動態(tài)分配的內(nèi)存塊的指針x,則可用如下的語句來獲知包含開始處struct struct _mem的x塊的大?。?struct struct _mem_ *pBlock; unsigned int blocksize; pBlock=x; blocksize=(struct struct _mem_ *)(&pBlock-1)-len+sizeof(struct struct _mem);而這正是free函數(shù)進行內(nèi)存回收時所要采用的技術(shù)。4.free函數(shù)分析及改進free函數(shù)的原形是void free (void xdata *memp); 參數(shù)memp指向所要釋放的內(nèi)存塊。在AVAIL鏈表中,各結(jié)點是按其所指空閑內(nèi)存塊的開始地址的大小按升序排列。free函數(shù)的算法是在AVAIL鏈表中查一個節(jié)點p(其前驅(qū)為q),當(dāng)p節(jié)點所指空存塊的地址大于參數(shù)memp所指內(nèi)存塊的起始地址時,則將memp塊插入到該節(jié)點之前,如沒有找到這樣的節(jié)點,則memp塊插到鏈尾。在插入memp塊時,還將檢查在memp塊的前后是否存在地址相鄰的空閑內(nèi)存塊,如果有,則將memp塊與相鄰塊合并。free庫函數(shù)的部分源代碼如下:void free ( void _MALLOC_MEM_ *memp)/前面省略p0 = memp;p0 = &p0 -1;/* 參考malloc函數(shù)的分析,&p0 -1為memp所指內(nèi)存塊首部的 struct _mem_結(jié)構(gòu)的地址,其中含有該塊內(nèi)存的大小信息,由調(diào)用malloc函數(shù)時填入*/q = &AVAIL;/查找p節(jié)點的代碼省略/部分代碼省略/*如果q塊與memp塊相鄰,則合并*/if (char _MALLOC_MEM_ *)q) + q-len + HLEN) = p0) q-len += p0-len + HLEN; q-next = p0-next; else q-next = p0; 值得探討的是最后一段將memp塊與前一塊(q塊)合并的這部分代碼。如果在執(zhí)行此部分代碼之前,q指向首結(jié)點AVAIL,而此時欲將q塊與memp塊合并顯然是不合理;實際上,此時本應(yīng)當(dāng)使q的next指針的值設(shè)為memp塊的開始地址p0。由于Keil C7.5A中free庫函數(shù)的源程序中沒有考慮這種特殊情況,可能會引發(fā)嚴(yán)重后果。由源代碼分析可知,在q指向首結(jié)點AVAIL,而此時如果滿足memp塊與q塊合并的判定條件,執(zhí)行q-len += p0-len + HLEN;q-next = p
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 精準(zhǔn)醫(yī)療合作治療項目合同
- 公司與個體房屋出租協(xié)議
- 山塘承包合同適用復(fù)雜情況
- 車輛礦石運輸合同
- 綠色建筑技術(shù)研發(fā)合同
- 新材料生產(chǎn)綠色環(huán)保技術(shù)應(yīng)用推廣合作協(xié)議
- Module 3 Journey to space Unit 1 (教學(xué)設(shè)計)-2023-2024學(xué)年外研版英語八年級下冊
- 月子中心房屋振動限制協(xié)議
- 13我能行 教學(xué)設(shè)計 -2023-2024學(xué)年道德與法治二年級下冊(統(tǒng)編版)
- 家具廠白蟻防治施工方案
- 高壓氧科工作總結(jié)高壓氧科個人年終總結(jié).doc
- 電子電路基礎(chǔ)習(xí)題解答
- 《政治學(xué)概論》教學(xué)大綱
- 食品生物化學(xué)習(xí)題謝達平(動態(tài))
- 保安員工入職登記表
- 斷路器控制回路超詳細講解
- 簽證戶口本完整翻譯模板
- 睿達RDCAM激光雕刻切割軟件V5.0操作說明書
- 變電設(shè)備運行與維護培訓(xùn)課件(共102頁).ppt
- 機械設(shè)計基礎(chǔ)平面連桿機構(gòu)課件
- 寒假學(xué)習(xí)計劃表-
評論
0/150
提交評論