版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、Good is good, but better carries it.精益求精,善益求善。KeilC動態(tài)內(nèi)存管理機制分析及改進(jìn)-2(6068a)KeilC動態(tài)內(nèi)存管理機制分析及改進(jìn)P74全文如下:KeilC動態(tài)內(nèi)存管理機制分析及改進(jìn)丁明亮熊真春摘要通過對C51中init_mempool,malloc,free三個函數(shù)源代碼的分析,深入分析C51的動態(tài)內(nèi)存管理機制,同時也給出一些使init_mempool函數(shù)更完善和除去free函數(shù)中的一個錯誤的建議。關(guān)鍵詞C51動態(tài)內(nèi)存管理分析Abstract:basedontheanalysistosourcesoffunctioninit_mempool
2、,mallocandfree,thisarticleprobesthedynamicmemorymanagementofC51Library,andgivesoutsomeadvicestobetterfunctioninit_mempoolandtoclearabugoffunctionfree.Keywords:C51dynamicmemorymanagement0.前言KeilC是常用的嵌入式系統(tǒng)編程工具,它通過init_mempool,mallloc,free等函數(shù),提供了動態(tài)存儲管理管理等功能。本文希望通過init_mempool,mallloc,free三個KeilC庫函數(shù)源代碼的
3、分析,揭示了其實現(xiàn)的原理和方法,也對其中的不足作了改進(jìn),以使KeilC編程人員更好地應(yīng)用動態(tài)存儲管理。1相關(guān)數(shù)據(jù)結(jié)構(gòu)、變量及說明在KeilC安裝目錄下的c51lib目錄下,有實現(xiàn)init_mempool,mallloc,free三個函數(shù)的C源文件init_mem.c,malloc.c,free.c,下面針對keilC7.5A版,將其中與動態(tài)存儲管理相關(guān)的數(shù)據(jù)結(jié)構(gòu)介紹如下:#define_MALLOC_MEM_xdata/*該行在stdlib.h文件中*/struct_mem_struct_mem_MALLOC_MEM_*next;/*單鏈表*/unsignedintlen;/*下一塊長度*/;
4、該結(jié)構(gòu)的next指向堆中的下一空閑內(nèi)存塊,len表示該空閑塊除去該塊首部的struct_mem_結(jié)構(gòu)所占的字節(jié)數(shù)后,該塊實際可用的字節(jié)數(shù)。由于next是一個指向XDATA區(qū)的指針,故在KeilC中應(yīng)用程序所定義的堆空間應(yīng)在XDATA段中定義。在KeilC中,堆中的所有的空閑內(nèi)存塊是用一個單鏈表來管理的,struct_mem_即為該鏈表結(jié)點的結(jié)構(gòu),后面定義的宏AVAIL為該鏈表的首結(jié)點,為敘述方便,以下將該鏈表稱為AVAIL鏈表。typedefstruct_mem_memt_;typedef_memt_MALLOC_MEM_*_memp_;_memt_MALLOC_MEM_mem_avail_2
5、=NULL,0,/*堆中空閑內(nèi)存塊頭結(jié)點*/NULL,0,/*未使用,但對free函數(shù)防止丟失堆空間或誤將鏈表頭加入到堆空間,卻是必須的*/*作者注:_mem_avail_1的存在,并不能防止堆丟失,見后面free函數(shù)分析*/;#defineAVAIL(_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。2init_mempool函數(shù)剖析函數(shù)intinit_
6、mempool(void_MALLOC_MEM_*pool,unsignedintsize)失敗時將返回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。其在KeilC7.5A庫中init_mem.c的源代碼如下所示。#defineHLEN(sizeof(_memt_)#defineMIN_PO
7、OL_SIZE(HLEN*10)intinit_mempool(void_MALLOC_MEM_*pool,unsignedintsize)if(sizenext=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)
8、存塊時,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è)為一個
9、形如0 xAAAA數(shù)字表示的絕對地址,如果不加特別防范,也是不妥的,因為KeilC可能會在你以如此方式指定的堆空間中分配臨時變量。好的習(xí)慣是定義一個字節(jié)數(shù)組作為堆空間,再將數(shù)組名作為pool參數(shù)調(diào)用init_mempool函數(shù)。在KeilC的聯(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)致一些很難診斷的問題。對這個問題,可采用如下的保護(hù)措施。當(dāng)發(fā)現(xiàn)AVAIL鏈表中
10、已有管理信息時,則返回失敗標(biāo)志,函數(shù)直接返回。具體的方法是檢查AVAIL結(jié)點的len域,由于其被初始化為零,如果發(fā)現(xiàn)其值非零,則表明init_mempool函數(shù)已被成功調(diào)用過,此時函數(shù)直接返回。3malloc函數(shù)分析malloc函數(shù)的原形是void*malloc(unsignedintsize);size參數(shù)為需動態(tài)申請的內(nèi)存塊的字節(jié)數(shù)。malloc函數(shù)的算法是查找AVAIL鏈表中各結(jié)點next指針?biāo)赶虻目臻e內(nèi)存塊,如果某塊的空閑的字節(jié)數(shù)=size參數(shù),則停止查找,并從該塊進(jìn)行內(nèi)存分配,返回一個指向所分配的內(nèi)存塊的指針給應(yīng)用程序,如果沒有找到合符要求的空閑內(nèi)存塊,則返回空指針給應(yīng)用程序。需要
11、注意的是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ù),則需對該塊進(jìn)行分割,將多出的這一部分保留在AVAIL鏈表中。下面是在malloc.c中該函數(shù)的
12、部分源代碼:#defineMIN_BLOCK(HLEN*4)void_MALLOC_MEM_*malloc(unsignedintsize)/省略k=p-len-size;/*計算分配后剩余的字節(jié)數(shù)*/if(knext=p-next;/*將p塊從AVAIL鏈表中刪除*/return(&p1);/*成功,參見后面分析*/*分割該塊*/k-=HLEN;p-len=k;q=(_memp_)(char_MALLOC_MEM_*)(&p1)+k);q-len=size;/*填入所分配塊的大小*/return(&q1);/*成功,參見下面分析*/在C語言中,數(shù)組名就是一個內(nèi)存地址,也可把一個指針當(dāng)作一個數(shù)
13、組名;同時C語言數(shù)組的下標(biāo)從0開始,在上面的源代碼中,q為structstruct_mem類型的指針,所以&q1的值等于q塊的起始地址+sizeof(structstruct_mem)的值,也就是說malloc通過return(&q1)語句返回給應(yīng)用程序的內(nèi)存塊指針,實際是指向所分配內(nèi)存塊偏移sizeof(structstruct_mem_)處的。假設(shè)我們的應(yīng)用程序中有一指向某動態(tài)分配的內(nèi)存塊的指針x,則可用如下的語句來獲知包含開始處structstruct_mem的x塊的大?。簊tructstruct_mem_*pBlock;unsignedintblocksize;pBlock=x;blo
14、cksize=(structstruct_mem_*)(&pBlock-1)-len+sizeof(structstruct_mem);而這正是free函數(shù)進(jìn)行內(nèi)存回收時所要采用的技術(shù)。4.free函數(shù)分析及改進(jìn)free函數(shù)的原形是voidfree(voidxdata*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塊插到鏈尾。在插
15、入memp塊時,還將檢查在memp塊的前后是否存在地址相鄰的空閑內(nèi)存塊,如果有,則將memp塊與相鄰塊合并。free庫函數(shù)的部分源代碼如下:voidfree(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;elseq-next=p0;值得探討的是最后一段將memp塊與前一塊(q塊)合并的這部分代碼。如果在執(zhí)行此部分代碼之前,q指向首結(jié)點AVAIL,而此時欲將q塊與memp塊合并顯然是不合理;實際上,此時本應(yīng)當(dāng)使q的next指針的值設(shè)為memp塊的開始地址p0。由于KeilC7.5A中free庫函數(shù)的源程序中沒有考慮這種特殊情況,可能會引發(fā)嚴(yán)重后果。由源代碼分析可知,在q指向首結(jié)點AVAIL,而此時如果滿足memp塊與q塊合并的判定條件,執(zhí)行q-len+=p0-len+HLEN
溫馨提示
- 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 南京工業(yè)大學(xué)《數(shù)字建筑概論》2023-2024學(xué)年第一學(xué)期期末試卷
- 西北地區(qū)和青藏地區(qū)教案第一課時
- 南京工業(yè)大學(xué)《民法》2022-2023學(xué)年第一學(xué)期期末試卷
- 炒鍋供貨合同范本
- 多方主體合同范本
- 店門分租合同范本
- 土地流轉(zhuǎn)合同范本山東
- 無產(chǎn)權(quán)車庫合同范本
- 吉林省吉林市2024-2025學(xué)年度高中畢業(yè)年級第一次模擬測試語文試題及參考答案
- 2024學(xué)校股權(quán)轉(zhuǎn)讓合同書
- 蘋果商店所有地區(qū)價格和等級表
- 【參考】華為騰訊職位管理0506
- 五年級英語上冊Unit1Getupontime!教案陜旅版
- 風(fēng)機安裝工程質(zhì)量通病及預(yù)防措施
- 三角形鋼管懸挑斜撐腳手架計算書
- 剪紙教學(xué)課件53489.ppt
- 旅游業(yè)與公共關(guān)系PPT課件
- 勞動法講解PPT-定稿..完整版
- 彩色的翅膀_《彩色的翅膀》課堂實錄
- 假如你愛我的正譜
- 銅芯聚氯乙烯絕緣聚氯乙烯護(hù)套控制電纜檢測報告可修改
評論
0/150
提交評論