文獻(xiàn)標(biāo)識(shí)碼: A
文章編號(hào): 0258-7998(2012)11-0034-03
內(nèi)存池方式的內(nèi)存管理是一種可計(jì)量、高效的內(nèi)存管理方式,,它具有減少內(nèi)存碎片,、提高分配速度、防止內(nèi)存泄漏等優(yōu)勢(shì)[1],。目前在國(guó)內(nèi)基于內(nèi)核的內(nèi)存池大多基于Linux內(nèi)核[2],。本文主要基于Nucleus操作系統(tǒng)內(nèi)核來(lái)介紹內(nèi)存池靜態(tài)與動(dòng)態(tài)分配在TD-LTE無(wú)線(xiàn)綜合測(cè)試儀移植中的研究與應(yīng)用,闡述了在不同分配方式中的內(nèi)存池結(jié)構(gòu),、分配算法以及適用環(huán)境,。
1 靜態(tài)方式分配內(nèi)存池
靜態(tài)內(nèi)存池管理方式中內(nèi)存池分為池(pool)和塊(partition)。之所以稱(chēng)之為靜態(tài)管理方式,,是因?yàn)樵谑褂眠^(guò)程中塊的大小是固定的(即在創(chuàng)建過(guò)程中塊大小是確定的),。靜態(tài)內(nèi)存池的整體結(jié)構(gòu)如圖1所示,池和塊都有自己的頭,,池是由雙向循環(huán)鏈表鏈接而成,,塊是由單向鏈表鏈接而成,每一塊的頭中還包含了自己屬于哪一個(gè)池的屬性,??捎脡K的信息以單向鏈表的形式存儲(chǔ)于池頭中,并且可用塊與已經(jīng)分配的塊的個(gè)數(shù)都在池頭中有記錄,。
1.1 靜態(tài)內(nèi)存池的創(chuàng)建
池頭中的主要參數(shù)包括內(nèi)存池控制塊指針,、內(nèi)存池名(只取8個(gè)字符)、起始地址,、內(nèi)存池總大?。ㄗ止?jié)為單位)、內(nèi)存池分塊大?。ㄗ止?jié)為單位),、掛起方式(先進(jìn)先出或按優(yōu)先級(jí))等,圖2是仿真器上運(yùn)行過(guò)程中靜態(tài)內(nèi)存池結(jié)構(gòu)體截圖,。
對(duì)圖2中兩個(gè)結(jié)構(gòu)體鏈表參數(shù)說(shuō)明如下:(1)pm_created:當(dāng)前已經(jīng)創(chuàng)建的內(nèi)存池,,采用雙向循環(huán)鏈表連接,插入方式是在最后一個(gè)節(jié)點(diǎn)和首節(jié)點(diǎn)間填充;(2)pm_available_list:存儲(chǔ)當(dāng)前還可用partition的鏈表,,結(jié)構(gòu)與塊的頭部結(jié)構(gòu)header_ptr相同(PM_OVERHEAD=8 B小塊的頭header_ptr:?jiǎn)蜗蜴湵?,?nèi)部有指向下一小塊的指針和所屬大塊的控制塊地址)。
在Nucleus內(nèi)核中,,內(nèi)存池的創(chuàng)建主要由函數(shù)PMC_Create_Partition_Pool負(fù)責(zé),,創(chuàng)建流程如下:調(diào)用過(guò)程中首先進(jìn)行參數(shù)合法性檢測(cè);然后在池頭(控制塊)中寫(xiě)入各個(gè)參數(shù),,創(chuàng)建鏈表,;之后是一個(gè)重要的循環(huán)體,負(fù)責(zé)初始化partition鏈表,,分配所有的partition,,每個(gè)partition的大小在分配時(shí)需要在函數(shù)傳入?yún)?shù)值的基礎(chǔ)上加8 B,用來(lái)存儲(chǔ)header_ptr,;最后在內(nèi)存池線(xiàn)程保護(hù)后將新的內(nèi)存池插入內(nèi)存池鏈表并計(jì)數(shù),。
1.2 靜態(tài)內(nèi)存池的分配
在TD-LTE無(wú)線(xiàn)綜合測(cè)試儀中分配前由協(xié)議棧提供所需要分配的大小,這里主要是放置協(xié)議內(nèi)部配置信息與層間交互原語(yǔ),。由于這些信息的大小固定,,只是有幾種不同大小的固定模式,所以很適合采用靜態(tài)分配的方式來(lái)分配內(nèi)存,,只需要根據(jù)數(shù)據(jù)大小選擇密度合適的內(nèi)存池即可,。移植過(guò)程中使用了不同大小的partition構(gòu)建不同密度的內(nèi)存池,因此,,可根據(jù)申請(qǐng)partition的大小來(lái)判定用那種密度的內(nèi)存池,,以減少內(nèi)部碎片的大小,。這種方法可以有效避免空間浪費(fèi)[3],,同時(shí)又可提高分配效率。
在Nucleus內(nèi)核中靜態(tài)內(nèi)存池的分配主要由函數(shù)PMC_Allocate_Partition負(fù)責(zé),,其主要參數(shù)為內(nèi)存池指針(指向調(diào)用的內(nèi)存指針,,不能為NULL,設(shè)置為可用內(nèi)存地址即可),、分配大小和掛起標(biāo)志位,。函數(shù)中主要判斷內(nèi)存池指針是否合法、內(nèi)存池與partition是否匹配,、指向調(diào)用的內(nèi)存指針是否合法,、任務(wù)掛起標(biāo)志位是否有效。其分配流程如圖3所示,。過(guò)程如下:調(diào)用內(nèi)核函數(shù)TCT_System_Protect(TCT_Protect)保護(hù)內(nèi)存池同步互斥通道,。判斷是否還有可用partition,若有,則將可用數(shù)量減1,、分配數(shù)量加1并更新pm_available_list以及將指向調(diào)用內(nèi)存指針賦值為當(dāng)前分配的partition地址(partition地址要+8 B刪去頭),;若沒(méi)有,則將任務(wù)掛起直至有可用Partition才恢復(fù),。最后解保護(hù)并返回,。
1.3 靜態(tài)內(nèi)存池的釋放
系統(tǒng)采用PMC_Deallocate_Partition函數(shù)來(lái)完成釋放。流程如下:調(diào)用內(nèi)核函數(shù)保護(hù)內(nèi)存池同步互斥通道,。判斷是否有等待任務(wù),,若有,則分配給這個(gè)任務(wù)當(dāng)前partition,,再判斷當(dāng)前任務(wù)是否允許被搶占,,允許就調(diào)用TCT_Control_To_System搶占當(dāng)前任務(wù)、激活等待內(nèi)存的任務(wù),;若沒(méi)有,,則等待任務(wù),將當(dāng)前partition重新接入到可用partition列表的頭部,。最后調(diào)用TCT_Unprotect解保護(hù),。
2 動(dòng)態(tài)方式分配內(nèi)存池
動(dòng)態(tài)內(nèi)存池也分為池和塊兩個(gè)部分,動(dòng)態(tài)池直接由雙向循環(huán)鏈表實(shí)現(xiàn)連接,。內(nèi)部塊是動(dòng)態(tài)分配的,,由最小可分配空間來(lái)限制塊的最小值。與靜態(tài)分配不同,,動(dòng)態(tài)分配塊也由雙向循環(huán)鏈表來(lái)鏈接,。創(chuàng)建時(shí)的初始結(jié)構(gòu)為兩個(gè)塊,在申請(qǐng)時(shí)動(dòng)態(tài)分割,。圖4是仿真器上運(yùn)行過(guò)程中動(dòng)態(tài)內(nèi)存池與塊的結(jié)構(gòu)體截圖,。
池控制塊結(jié)構(gòu)中dm_memory_list與塊頭結(jié)構(gòu)體相同,池通過(guò)dm_memory_list來(lái)完成塊搜索,;塊頭結(jié)構(gòu)中dm_memory_pool與大塊頭結(jié)構(gòu)相同,,通過(guò)它來(lái)比配大塊。
2.1 動(dòng)態(tài)內(nèi)存池的創(chuàng)建
初始化完成時(shí)的內(nèi)存結(jié)構(gòu):初始化創(chuàng)建完成時(shí)內(nèi)存池中有2個(gè)塊,,1個(gè)大小為總大小減去32 B,,包含自己的頭DM_OVERHEAD=16 B,設(shè)置為可以狀態(tài)free=‘0x01’,;1個(gè)大小為16 B,,只有自己的頭,沒(méi)有空間,,設(shè)置為不可以狀態(tài)free=‘0x00’,。因此,,此時(shí)的可用空間為除去池的控制塊外的總大小減去32 B。初始化結(jié)構(gòu)如圖5所示(沒(méi)有將池控制塊表示出來(lái)),。
創(chuàng)建時(shí),,首先為控制塊指針賦值,內(nèi)存池大小與最小分區(qū)大小進(jìn)行字對(duì)齊校正,;判斷控制塊指針,、起始地址、最小分配空間,、掛起標(biāo)志是否合法,。創(chuàng)建過(guò)程如下:初始化控制塊中的各個(gè)參數(shù),并按圖5初始化小塊,、創(chuàng)建小塊雙向循環(huán)鏈表,,與靜態(tài)分配相同需要先進(jìn)行線(xiàn)程保護(hù)再加入到池動(dòng)態(tài)內(nèi)存池鏈表,。
2.2 動(dòng)態(tài)內(nèi)存池的申請(qǐng)
動(dòng)態(tài)申請(qǐng)主要用于操作系統(tǒng)內(nèi)模塊(如任務(wù),、隊(duì)列等)的堆棧分配與模塊占用空間的分配。由于在TD-LTE無(wú)線(xiàn)綜合測(cè)試儀中這些分配的空間大小浮動(dòng)不定,,因此需要使用動(dòng)態(tài)分配內(nèi)存。Nucleus中動(dòng)態(tài)分配采用首次匹配原則,,每一次申請(qǐng)內(nèi)存時(shí)動(dòng)態(tài)分配申請(qǐng)大小加16 B(這個(gè)16 B的頭對(duì)應(yīng)剩下的可用空間)的內(nèi)存池空間,,并把分配過(guò)的部分設(shè)置為不可用狀態(tài)free=‘0x00’,。
負(fù)責(zé)實(shí)現(xiàn)的函數(shù)是DMC_Allocate_Memory。首先進(jìn)行各種參數(shù)的合法性檢測(cè),,然后將分配空間size小于最小分配空間的分配空間大小賦值為最小空間,,對(duì)size進(jìn)行字對(duì)齊處理,,調(diào)用線(xiàn)程保護(hù)后采用首先匹配法來(lái)找適用空間,,即:在循環(huán)體中先判斷free標(biāo)志,,是空閑塊(free=‘0x01’),,則算出減去本次分配的頭后所剩的空間,,當(dāng)此空間大于本次請(qǐng)求size時(shí)進(jìn)行分配,,小于時(shí)則移動(dòng)到下一個(gè)塊,;若不是空閑塊,,則直接把剩余空間設(shè)置為0進(jìn)行后面小于size時(shí)移動(dòng)到下一個(gè)塊的判斷,。注意:這里用到了控制塊中的dm_search_ptr屬性(結(jié)構(gòu)與小塊的頭相同),,該屬性用于記錄開(kāi)始匹配的起始位置,,作為判斷循環(huán)體結(jié)束的條件之一,,如果循環(huán)到此處,就表示沒(méi)有找到可分配空間,。圖6是動(dòng)態(tài)分配的流程圖,。
循環(huán)結(jié)束后判斷是否找到可用于分配的塊,,若找到則進(jìn)行是否需要分割該可用塊的判斷,。條件是這個(gè)可用塊的大小大于或等于本次所需空間size+頭大小+最小分配空間的值,若滿(mǎn)足此條件則分割出一個(gè)新塊并對(duì)其加頭初始化,,再計(jì)算出剩余可用空間,;不滿(mǎn)足此條件則直接計(jì)算剩余可用空間。分配的空間標(biāo)志為非空閑后,,把所分配空間的地址賦給指向調(diào)用的內(nèi)存指針(注意去頭),。為提高效率,還需要進(jìn)行一個(gè)簡(jiǎn)單處理,,即判斷如果在搜索塊時(shí)一次性匹配成功,,則將dm_search_ptr移向下一個(gè)塊。
如果沒(méi)有找到可用塊則將任務(wù)掛起等待,,沒(méi)有采用掛起模式則直接返回NULL給指向調(diào)用的內(nèi)存指針,,最后調(diào)用TCT_Unprotect解保護(hù),。圖7是分配第一塊內(nèi)存后動(dòng)態(tài)內(nèi)存池的結(jié)構(gòu),。
2.3 動(dòng)態(tài)內(nèi)存池的釋放
釋放過(guò)程與靜態(tài)類(lèi)似,,需要注意的是,,如果相鄰塊有空閑塊需要合并,則合并后把dm_search_ptr指向當(dāng)前合并的空閑塊,。
動(dòng)態(tài)分配內(nèi)存的算法復(fù)雜度要高于靜態(tài)分配,,從時(shí)間復(fù)雜度來(lái)看,,靜態(tài)分配是O(1),、動(dòng)態(tài)是O(n),。但是動(dòng)態(tài)分配的內(nèi)存利用率要高于靜態(tài)分配內(nèi)存[5],在實(shí)際應(yīng)用中要結(jié)合具體情況決定采用何種分配方式,。在本設(shè)計(jì)中合理使用了兩種分配方式:在靜態(tài)分配中進(jìn)行密度的動(dòng)態(tài)判斷,在動(dòng)態(tài)分配中進(jìn)行靜態(tài)的最小分配大小匹配,。動(dòng),、靜相結(jié)合,使操作系統(tǒng)在分配中盡可能地節(jié)約內(nèi)存的同時(shí),,有效減少了內(nèi)存碎片,。本分配方式已經(jīng)運(yùn)用于TD-LTE無(wú)線(xiàn)綜合測(cè)試儀中,,在實(shí)現(xiàn)操作系統(tǒng)基本內(nèi)存管理功能的同時(shí),,滿(mǎn)足了TD-LTE無(wú)線(xiàn)綜合測(cè)試儀對(duì)系統(tǒng)內(nèi)存資源和調(diào)度時(shí)間的設(shè)計(jì)要求,。
參考文獻(xiàn)
[1] 馮寶祥,,王桂棠.嵌入式實(shí)時(shí)操作系統(tǒng)Nucleus PLUS在S3C2410A上移植的實(shí)現(xiàn)[J].電子設(shè)計(jì)應(yīng)用,,2007(5):104-106.
[2] 王小銀,,陳莉君.Linux內(nèi)核中內(nèi)存池的實(shí)現(xiàn)及應(yīng)用[J]. 西安郵電學(xué)院學(xué)報(bào),,2001,,16(4):40-43.
[3] 張磊,,王忠仁.嵌入式系統(tǒng)中一種池式內(nèi)存管理中應(yīng)用 [J].實(shí)驗(yàn)科學(xué)與技術(shù),,2007,5(2):150-152
[4] LMAS S H.An application-level memory management service[C].ICTTA 2008.3rd International Conference on.7-11 April 2008:1-4.
[5] MUTSCHLER D W.Enhancement of memory pools toward a multi-threaded implementation of the Joint integrated mission model(JIMM)[C].WSC 06.Proceedings of the Winter.3-6 Dec.2006:856-862.