專利名稱:嵌入式系統(tǒng)高效內(nèi)存池的實現(xiàn)方法
技術(shù)領(lǐng)域:
本發(fā)明涉及嵌入式系統(tǒng)的內(nèi)存管理機(jī)制,具體涉及嵌入式系統(tǒng)高效內(nèi)存池的實現(xiàn) 方法。
背景技術(shù):
嵌入式系統(tǒng)的內(nèi)存管理機(jī)制必須滿足實時、高效、高可靠性的要求。具體體現(xiàn)在(1)快速,嵌入式系統(tǒng)由于要保證實時性,因此要求內(nèi)存分配過程盡可能地快。(2)高效,內(nèi)存分配要盡可能減少占用開銷。(3)可靠,內(nèi)存分配必須得到滿足,如果分配失敗可能會帶來災(zāi)難性的后果。目前,嵌入式系統(tǒng)常用的內(nèi)存管理方式有以下3種(1)固定式分配,也叫靜態(tài)分配或預(yù)分配。適用于那些不能夠承擔(dān)內(nèi)存耗盡風(fēng)險, 或者實時性要求特別高的應(yīng)用程序。在程序初始化的時候,預(yù)先分配固定數(shù)量的內(nèi)存,用于 存儲所需要的對象和數(shù)據(jù)結(jié)構(gòu),比如使用數(shù)組。(2)動態(tài)分配。根據(jù)需要從內(nèi)存堆(heap)(在C/C++中,堆是指一般由程序員分 配和釋放,若程序員不釋放,程序結(jié)束時可能由OS回收。其分配和釋放函數(shù)一般是new、 malloc、delete、free等)中分配內(nèi)存。內(nèi)存堆動態(tài)分配內(nèi)存的一些分配算法會花費不可 預(yù)期的時間。申請的區(qū)塊越小,額外負(fù)擔(dān)所占用的比例就越大。在這種方式下,還必須準(zhǔn)備 好處理內(nèi)存耗盡的情況,例如某個系統(tǒng)X有兩個模塊協(xié)作處理一個業(yè)務(wù),處理業(yè)務(wù)時各個 模塊都需要為每條業(yè)務(wù)分配一個不同的對象,如果每個模塊都采用動態(tài)分配內(nèi)存方案,在 業(yè)務(wù)高峰時,可能第一個處理模塊就將系統(tǒng)內(nèi)存分配光了,因此,第二個模塊處理時無法分 配內(nèi)存,導(dǎo)致業(yè)務(wù)流程處理中斷,從而造成所有業(yè)務(wù)都沒有得到處理。鑒于以上各種原因, 嵌入式系統(tǒng)很少直接采用動態(tài)分配技術(shù)。(3)內(nèi)存池式分配。內(nèi)存池一般用來分配某種固定尺寸的反復(fù)多次分配和釋放的 特定內(nèi)存塊。嵌入式系統(tǒng)內(nèi)存分配的常用手段原則上采取二級配置第1級配置直接采用 操作系統(tǒng)提供的手段(比如通過語句mallocO和freeO)分配好所需要的內(nèi)存;第2級配 置采用內(nèi)存池管理方式,內(nèi)存池維護(hù)著空閑內(nèi)存鏈表。預(yù)先分配一個內(nèi)存池,循環(huán)使用其中 未被使用的內(nèi)存塊,此時應(yīng)注意預(yù)先分配足夠的內(nèi)存,以便能夠在程序啟動時容納大量的 數(shù)據(jù)結(jié)構(gòu),通過建立自由鏈表,可以避免內(nèi)存塊頭部額外字節(jié)的消耗,從而可以改變動態(tài)內(nèi) 存分配的內(nèi)存管理器中額外開銷。這種二級分配方式還盡量減少了內(nèi)存碎片,使得能夠在 一定的內(nèi)存中存儲更多的數(shù)據(jù)結(jié)構(gòu),減少系統(tǒng)的整體內(nèi)存需求,降低系統(tǒng)成本。在前面例子 系統(tǒng)X中,如果所有模塊都采用內(nèi)存池式分配方案,在初始化時就為每個模塊預(yù)分配了一 定數(shù)量A的對象;在業(yè)務(wù)高峰時,系統(tǒng)中已經(jīng)沒有內(nèi)存可以分配,第一個處理模塊只會處理 A條業(yè)務(wù),超過A的業(yè)務(wù)遭到丟棄;第二個模塊也可以從內(nèi)存池中分配A個對象,也可以處 理A條業(yè)務(wù)。所以采用內(nèi)存池實現(xiàn)方案,至少可以保證一定業(yè)務(wù)。目前在內(nèi)存池或者緩沖區(qū)實現(xiàn)的相關(guān)專利文獻(xiàn)中或者側(cè)重于提高內(nèi)存管理模塊 的效率,或者側(cè)重于最大化內(nèi)存的利用率(最小化管理開銷占用的內(nèi)存),或者側(cè)重于減少內(nèi)存碎片,或者側(cè)重于實現(xiàn)內(nèi)存池的動態(tài)擴(kuò)展和回收,或者側(cè)重于增加內(nèi)存的可調(diào)試性,提 供檢測內(nèi)存越界、內(nèi)存泄漏的功能。以上這些方法側(cè)重于優(yōu)化內(nèi)存池每次申請和釋放內(nèi)存 塊時對內(nèi)存塊的快速搜索定位方法,從而提高內(nèi)存塊分配和釋放的速度。但很少有專利結(jié) 合內(nèi)存塊的初始化與銷毀以及提供避免數(shù)據(jù)無用拷貝機(jī)制來提高內(nèi)存塊分配速度。內(nèi)存池作為內(nèi)存塊的一個容器,存放空閑的內(nèi)存塊和內(nèi)存池管理需要的數(shù)據(jù)。內(nèi) 存池提供給使用者使用的通常是內(nèi)存塊。一般內(nèi)存池使用方法如下,首先創(chuàng)建內(nèi)存池,從內(nèi) 存池中分配內(nèi)存塊,使用內(nèi)存塊,釋放內(nèi)存塊回內(nèi)存池,在內(nèi)存池不再使用時,銷毀內(nèi)存池。 一個內(nèi)存塊的生命周期包括分配、使用和釋放。在程序運行期間,一個內(nèi)存池的創(chuàng)建一般只 執(zhí)行一次,通常在程序初始化時執(zhí)行,其銷毀一般也只執(zhí)行一次,或者根本不執(zhí)行(在程序 終結(jié)或者系統(tǒng)終結(jié)時,讓系統(tǒng)自動銷毀分配的資源)。然而在程序運行期間,一個內(nèi)存塊的 生命周期要重復(fù)無數(shù)次。所以為了提高效率,總是著眼于提高內(nèi)存塊的每次分配和釋放速 度。上面講到的內(nèi)存池中內(nèi)存塊的生命周期分為分配、使用和釋放三個階段,又可以 細(xì)分為以下五個階段,其包括1)從內(nèi)存池中分配內(nèi)存塊;2)初始化和構(gòu)造內(nèi)存塊; 3)使用內(nèi)存塊;4)析構(gòu)和銷毀內(nèi)存塊;5)將內(nèi)存塊釋放到內(nèi)存池中。內(nèi)存塊通常被使用者作為數(shù)據(jù)結(jié)構(gòu)指針使用,其被分配后一般都立即強(qiáng)制轉(zhuǎn)換成 該數(shù)據(jù)結(jié)構(gòu)指針。許多頻繁復(fù)雜的數(shù)據(jù)結(jié)構(gòu)包含一個或者多個成員變量。其中一些變量 的初始化和銷毀會消耗大量資源,像鎖、信號量以及其它可以當(dāng)作初始化狀態(tài)的變量(像 嵌套的內(nèi)存指針(隨后立即需要分配內(nèi)存)等),我們將這些成員變量叫做非易變成員變 量;除此以外的簡單成員變量叫做易變成員變量。例如在下面的數(shù)據(jù)結(jié)構(gòu)中,stream是 一個流的控制結(jié)構(gòu),其中data_ptr是指向數(shù)據(jù)緩沖區(qū)的指針;startp和endp是數(shù)據(jù)相對 于data_ptr的偏移量;tpye是流的類型;buf_siZe是數(shù)據(jù)緩沖區(qū)的大?。籩xtjxif是額外 分配的緩沖區(qū);databUf_embed是長度為256字節(jié)的數(shù)據(jù)緩沖區(qū),內(nèi)嵌在流的控制結(jié)構(gòu)中。 databuf_embed中可以存放小于等于256字節(jié)的數(shù)據(jù),data_ptr指向databuf_embed,buf_ size是256字節(jié);如果流的數(shù)據(jù)大于256字節(jié)或者數(shù)據(jù)緩沖區(qū)需要獨立于流控制結(jié)構(gòu)單 獨在不同模塊傳遞,就無法在databUf_embed中存放,就需要額外分配一塊內(nèi)存作為數(shù)據(jù) 緩沖區(qū),ext_buf> data_ptr指向該數(shù)據(jù)緩沖區(qū),buf_size就是額外分配的大?。涣骺刂平Y(jié) 構(gòu)的type也就有兩種,一種是數(shù)據(jù)緩沖區(qū)內(nèi)嵌,一種是數(shù)據(jù)緩沖區(qū)額外分配。其中,變量 type、startp> endp、buf_size> data_ptr、databuf_embed 就是數(shù)據(jù)結(jié)構(gòu)的易變成員變量; 鎖lock、信號量sem、ext_buf是數(shù)據(jù)結(jié)構(gòu)的非易變成員變量。struct stream{MUTEX^lock ;SEMPHORE^sem ;Int type ;/*type of stream氺/
Int startp ;/*first data position氺/Int endp ;/氺last valid data position氺/Int buf size ;/*size of data buf氺/unsigned char*data_ptr 氺pointer of data buf*/unsigned char氺ext_buf ;/氺pointer of extend buf*/char databuf_embed[64];};
在程序運行期間,內(nèi)存塊會無數(shù)次被分配和釋放,無數(shù)次重復(fù)上述生命周期的5 個階段。如果每次分配后都要對數(shù)據(jù)結(jié)構(gòu)中的非易變成員變量進(jìn)行初始化,在每次釋放前 又將這些數(shù)據(jù)結(jié)構(gòu)的非易變成員變量銷毀,則某些復(fù)雜數(shù)據(jù)結(jié)構(gòu)中非易變成員變量的初始 化和銷毀所需的時間大大超過了從內(nèi)存池中對其進(jìn)行分配和釋放回內(nèi)存池所需的時間,甚 至具有數(shù)量級的差異,導(dǎo)致系統(tǒng)效率低下甚至不可用。內(nèi)存池中內(nèi)存塊的分配和釋放通常是基于鏈表的操作或者其它快速定位算法,效 率非常高,分配和釋放時用于互斥的PV操作成了一種重要開銷。但在某些情況下,不需要 互斥(像單任務(wù)環(huán)境下,或者在某種已經(jīng)存在互斥的環(huán)境下),所以內(nèi)存池實現(xiàn)需要提供一 種可選項,內(nèi)存池使用者可以自行決定分配和釋放是否使用互斥。在某些應(yīng)用中,為了提高性能,需盡量避免數(shù)據(jù)拷貝,因此,多個使用者只讀使用 一個內(nèi)存塊數(shù)據(jù)時,一般共享該內(nèi)存塊數(shù)據(jù),只有在寫時才分配新的內(nèi)存塊將該內(nèi)存塊的 數(shù)據(jù)拷貝到新的內(nèi)存塊里。這樣節(jié)省了內(nèi)存占用,減少了數(shù)據(jù)拷貝。為了達(dá)到此目的,廣泛 使用引用計數(shù)。引用計數(shù)用來識別內(nèi)存塊是否正在使用,一般來說,每個內(nèi)存塊對應(yīng)一個弓I 用計數(shù),內(nèi)存塊的引用計數(shù)初始化為0,當(dāng)使用者使用一個內(nèi)存塊時,引用計數(shù)加1,使用完 后首先引用計數(shù)減1,然后檢查應(yīng)用計數(shù),當(dāng)引用計數(shù)為0,將內(nèi)存塊釋放到內(nèi)存池中;當(dāng)引 用計數(shù)不為0,表示有其他使用者正在使用該內(nèi)存塊,不釋放內(nèi)存塊到內(nèi)存池。在前面的流控制結(jié)構(gòu)的例子中,其數(shù)據(jù)緩沖區(qū)既可以嵌入在控制結(jié)構(gòu)中,也可以 和控制結(jié)構(gòu)分離。因此流控制結(jié)構(gòu)的類型有兩種,一種是數(shù)據(jù)緩沖區(qū)內(nèi)嵌,我們將這種流控 制結(jié)構(gòu)稱作STREAM_DATA_EMBED ;—種是數(shù)據(jù)緩沖區(qū)是額外分配的內(nèi)存,我們將這種流控 制結(jié)構(gòu)稱作STREAM_DATA_EXTEND。兩種流控制結(jié)構(gòu)都使用前面相同的數(shù)據(jù)結(jié)構(gòu)stream,但 其存放數(shù)據(jù)的數(shù)據(jù)緩沖區(qū)位置不同,使用的目的也不同;數(shù)據(jù)緩沖區(qū)的分配、釋放也不同。 針對這些不同,我們可以簡單地使用兩個不同的內(nèi)存池來緩存這兩種不同類型的流控制結(jié) 構(gòu),對數(shù)據(jù)緩沖區(qū)的分配、釋放也作不同的處理。但這兩種類型的流控制結(jié)構(gòu)都使用相同的 數(shù)據(jù)結(jié)構(gòu),并且其包含的變量除了 eXt_buf外,其他都是類似的。并且在使用者使用過程 中,要求兩者可以互相轉(zhuǎn)化。如果將其它模塊的數(shù)據(jù)緩沖區(qū)直接附加到一個STREAM_DATA_ EMBED中,其就變成了 一個STREAM_DATA_EXTEND流控制結(jié)構(gòu),在使用完后,就可以將其釋放 到緩存STREAM_DATA_EXTEND的內(nèi)存池中;如果要將STREAM_DATA_EXTEND的中的數(shù)據(jù)緩沖 區(qū)剝離后單獨傳遞給其他模塊,其就變成了 STREAM_DATA_EMBED的流控制結(jié)構(gòu),在使用完 后,就可以將其釋放到緩存STREAM_DATA_EMBED的內(nèi)存池中。數(shù)據(jù)緩沖區(qū)獨立于控制結(jié)構(gòu) 可以避免數(shù)據(jù)的拷貝。簡單的使用兩個內(nèi)存池割裂了兩者的共性并且無法解決其互相轉(zhuǎn)換 的問題。內(nèi)存池分配也有從系統(tǒng)中預(yù)分配內(nèi)存和從系統(tǒng)中動態(tài)分配內(nèi)存兩種方案。從系統(tǒng)中預(yù)分配內(nèi)存,就是創(chuàng)建內(nèi)存池時從系統(tǒng)中預(yù)先分配一大塊內(nèi)存,并分割成塊,然后添加到 內(nèi)存池的未初始化鏈表中,這樣以后每次分配內(nèi)存塊時,不用從系統(tǒng)中分配內(nèi)存,內(nèi)存塊的 分配時間存在確定性,不會出現(xiàn)在系統(tǒng)中分配不到內(nèi)存的情況,內(nèi)存塊的分配有保證;但其 缺點是,難以擴(kuò)展和回收。從系統(tǒng)中動態(tài)分配內(nèi)存就是創(chuàng)建內(nèi)存池時,沒有從系統(tǒng)中預(yù)分配 內(nèi)存,每次分配內(nèi)存塊時,如果內(nèi)存池中沒有可用的內(nèi)存塊,就從系統(tǒng)中分配一個內(nèi)存塊; 這樣的內(nèi)存池可以擴(kuò)展和回收;缺點是內(nèi)存塊分配會花費不可預(yù)期的時間,無法保證實時 性,此外還必須面對無法從系統(tǒng)分配內(nèi)存的情況。綜上所述,現(xiàn)有的嵌入式系統(tǒng)內(nèi)存池管理沒有考慮在內(nèi)存塊的初始化和釋放過程 中,對非易變成員變量的初始化和銷毀所占用資源大大超過簡單分配和釋放所占用的資 源,并且沒有提供一些機(jī)制來避免數(shù)據(jù)無效拷貝,無法很好地滿足系統(tǒng)實時、高效和高可靠 性的要求。
發(fā)明內(nèi)容
本發(fā)明所要解決的技術(shù)問題是解決嵌入式系統(tǒng)內(nèi)存池管理無法很好地滿足系統(tǒng) 實時、高效和高可靠性要求的問題。為了解決上述技術(shù)問題,本發(fā)明所采用的技術(shù)方案是提供一種嵌入式系統(tǒng)高效內(nèi) 存池的實現(xiàn)方法,該內(nèi)存池中的每個內(nèi)存塊的生命周期包括分配、使用和釋放三個階段,內(nèi) 存塊的分配階段包括以下步驟
步驟101、判斷內(nèi)存池中是否存在緩存內(nèi)存塊,如果存在則執(zhí)行步驟102,否則執(zhí) 行步驟103 ;步驟102、從上述緩存內(nèi)存塊中分配內(nèi)存塊,然后轉(zhuǎn)至步驟105 ;步驟103、從內(nèi)存池未初始化內(nèi)存塊鏈表中分配內(nèi)存塊;步驟104、初始化內(nèi)存塊非易變成員部分;步驟105、構(gòu)造內(nèi)存塊,初始化內(nèi)存塊中易變成員部分;內(nèi)存塊的釋放階段包括以下步驟步驟107、使內(nèi)存塊中的非易變成員回歸到初始化狀態(tài);步驟108、將內(nèi)存塊釋放到內(nèi)存池中。上述方案中,內(nèi)存池的數(shù)據(jù)結(jié)構(gòu)中保存了內(nèi)存池創(chuàng)建函數(shù)的四個回調(diào)函數(shù)指針, 非易變成員初始化函數(shù)mp_init、非易變成員終結(jié)函數(shù)mp_fini、構(gòu)造函數(shù)mp_ctor和析構(gòu) 函數(shù)mp_dt0r指針,非易變成員的初始化通過調(diào)用mp_init實現(xiàn),其銷毀通過調(diào)用mp_f ini 實現(xiàn);易變成員初始化通過調(diào)用mp_ctor實現(xiàn),其銷毀通過調(diào)用mp_dt0r實現(xiàn)。這四個函數(shù) 指針組合在一起決定了一個數(shù)據(jù)結(jié)構(gòu)哪些成員是非易變成員,哪些是易變成員,以及如何 對這些成員如何初始化和銷毀。這四個回調(diào)函數(shù)指針是使用者創(chuàng)建內(nèi)存池時傳遞給內(nèi)存池 實現(xiàn)模塊的,其由使用者實現(xiàn),所以是使用者決定了數(shù)據(jù)結(jié)構(gòu)哪些成員是非易變成員,哪些 是易變成員,以及如何對這些成員如何初始化和銷毀。從而達(dá)到對易變成員和非易變成員 的初始化和銷毀分開處理。本發(fā)明實現(xiàn)了一種高效通用內(nèi)存池技術(shù),與系統(tǒng)提供的內(nèi)存分配和釋放調(diào)用比 較,性能有極大的提高,特別是在復(fù)雜內(nèi)存結(jié)構(gòu)的分配和釋放上,性能具有數(shù)量級的提高。 在許多嵌入式軟件項目中,存在很多低效的內(nèi)存分配代碼,如果采用本專利實現(xiàn)的內(nèi)存池技術(shù),將極大提高代碼性能。同時本專利實現(xiàn)了互斥保護(hù)選項、內(nèi)存塊的引用計數(shù)、預(yù)分配 與動態(tài)分配可選及可結(jié)合機(jī)制、主輔內(nèi)存池機(jī)制、內(nèi)存池使用統(tǒng)計和錯誤檢測、空閑內(nèi)存塊 回收高級特性,這些高級特性在大型復(fù)雜系統(tǒng)中具有廣泛的用途。
圖1為本發(fā)明提供的的高效內(nèi)存池實現(xiàn)方法中的內(nèi)存塊生命周期示意圖;圖2為本發(fā)明提供的高效內(nèi)存池數(shù)據(jù)結(jié)構(gòu)圖;圖3為本發(fā)明提供的高效內(nèi)存池實現(xiàn)方法創(chuàng)建函數(shù)流程圖;圖4為本發(fā)明提供的高效內(nèi)存池實現(xiàn)方法內(nèi)存塊分配函數(shù)流程圖;圖5為本發(fā)明提供的高效內(nèi)存池實現(xiàn)方法內(nèi)存塊釋放函數(shù)流程圖; 圖6為本發(fā)明提供的高效內(nèi)存池實現(xiàn)方法內(nèi)存池銷毀函數(shù)流程圖;圖7為本發(fā)明提供的高效內(nèi)存池實現(xiàn)方法副內(nèi)存池創(chuàng)建函數(shù)流程圖;圖8為本發(fā)明提供的高效內(nèi)存池實現(xiàn)方法從參考內(nèi)存池中借用內(nèi)存塊函數(shù)流程 圖;圖9為本發(fā)明提供的高效內(nèi)存池實現(xiàn)方法內(nèi)存塊引用計數(shù)查找函數(shù)流程圖。
具體實施例方式本發(fā)明提供了一種嵌入式系統(tǒng)高效內(nèi)存池的實現(xiàn)方法,利用該方法,可以大大減 少內(nèi)存池中內(nèi)存塊的初始化和銷毀所需的時間,并且通過引用計數(shù)、副內(nèi)存池機(jī)制避免數(shù) 據(jù)的無益拷貝,提高了嵌入式系統(tǒng)的內(nèi)存使用效率,從而最大限度地滿足了嵌入式系統(tǒng)實 時性、高效性和高可靠性的要求。本發(fā)明的思路是針對非易變成員和易變成員采用不同的處理方法,圖1為該方法 中的內(nèi)存塊生命周期示意圖,結(jié)合圖1所示,該方法包括以下步驟步驟101、通過CachecLnums是否為0判斷內(nèi)存池中是否存在已經(jīng)初始化了的緩存 內(nèi)存塊(特指非易變成員已經(jīng)初始化的內(nèi)存塊),如果存在則執(zhí)行步驟102,否則執(zhí)行步驟 103 ;步驟102、從上述緩存內(nèi)存塊中分配內(nèi)存塊供非易變成員使用,然后轉(zhuǎn)至步驟 105 ;步驟103、從內(nèi)存池未初始化內(nèi)存塊鏈表中分配一個未初始化的內(nèi)存塊(特指非 易變成員未初始化的內(nèi)存塊);步驟104、調(diào)用mp_init初始化內(nèi)存塊供非易變成員使用;步驟105、調(diào)用mp_Ctor構(gòu)造內(nèi)存塊,并初始化;步驟106、使用內(nèi)存塊;步驟107、調(diào)用mp_dt0r使非易變成員占用的內(nèi)存塊的回歸到初始化狀態(tài);步驟108、將內(nèi)存塊釋放到內(nèi)存池中。下面對上述方法作出進(jìn)一步的詳細(xì)說明,上述方法包括內(nèi)存池的創(chuàng)建、從內(nèi)存池 中分配內(nèi)存塊、使用內(nèi)存塊、釋放內(nèi)存塊和當(dāng)內(nèi)存池不再使用時銷毀內(nèi)存池五個步驟。接下來以一個內(nèi)存池的具體實例加以具體說明。內(nèi)存池mem_pool_t20的數(shù)據(jù)結(jié)構(gòu)結(jié)構(gòu)如圖2所示,其中
200-內(nèi)存池名稱name ;201-后繼內(nèi)存池指針Next_p00l,該指針指向下一個內(nèi)存池;202-參考內(nèi)存池指針Ref_pool,用于實現(xiàn)副內(nèi)存池機(jī)制;203-統(tǒng)計信息成員,用于存放本內(nèi)存池使用情況的統(tǒng)計數(shù)據(jù);204-回調(diào)函數(shù)指針,包括mp_init初始化函數(shù)指針2041、mp_fini終結(jié)函數(shù)指針 2042、mp_ctor構(gòu)造函數(shù)指針2043和mp_dtor析構(gòu)函數(shù)2044四個函數(shù)指針,其中,mp_init 用于初始化內(nèi)存塊中的非易變成員,一般只調(diào)用一次;mp_fini用于銷毀內(nèi)存塊中的非易 變成員,一般只調(diào)用一次,并且是在將內(nèi)存塊釋放到一級內(nèi)存配置器前調(diào)用;mp_ctor用于 初始化內(nèi)存塊中的易變成員,每次分配內(nèi)存塊時都要調(diào)用;mp_dt0r用于銷毀內(nèi)存塊中的 易變成員,每次釋放內(nèi)存塊時都要調(diào)用,析構(gòu)函數(shù)mp_dt0r的另外一個作用是將內(nèi)存塊中 的非易變成員還原為初始化狀態(tài),例如非易變成員中的計數(shù)信號量,就需要在mp_dt0r里 對此計數(shù)信號量清零。
205-預(yù)分配信息,包括預(yù)分配內(nèi)存塊的起始地址2051,用于記錄從一級內(nèi)存配置 器中分配的內(nèi)存塊的起始地址;預(yù)分配內(nèi)存塊的基線地址2052,用于記錄2051對齊后的地 址;預(yù)分配內(nèi)存塊的數(shù)量2053,用于確定預(yù)分配內(nèi)存的大小。上述預(yù)分配信息用于查找引 用計數(shù)、判定內(nèi)存塊是否能夠回收以及在內(nèi)存塊銷毀時判定一個內(nèi)存塊是預(yù)分配的還是動 態(tài)分配的;206-引用計數(shù)數(shù)組指針,其指向附加部分中計數(shù)數(shù)組的地址。如果創(chuàng)建函數(shù)參數(shù) 的引用計數(shù)標(biāo)志位為置位,則在附加部分為引用計數(shù)數(shù)組保留內(nèi)存,并且206指向附加部 分中引用計數(shù)數(shù)組地址;如果未置位,引用計數(shù)數(shù)組指針為空;207-緩存的內(nèi)存塊個數(shù)Cached_nums ;208-緩存內(nèi)存塊數(shù)組指針CaChed_bl0CkS_ptr,用于指向附加部分中緩存內(nèi)存塊 數(shù)組;209-未初始化內(nèi)存塊鏈表指針uninitiated_liSt_ptr,其指向附加部分中未初 始化內(nèi)存塊鏈表;20a_鎖指針,其指向附加部分中鎖的地址。如果創(chuàng)建函數(shù)參數(shù)的鎖標(biāo)志位置位,則 在附加部分為鎖保留內(nèi)存,并且20a指向附加部分中鎖地址;如果未置位,20a為空。對內(nèi) 存池的操作需要判斷鎖是否非空決定是否加鎖和解鎖;20b-附加部分,即圖3中背景為斜線的部分,或者因為內(nèi)存池數(shù)據(jù)結(jié)構(gòu)中有的成 員大小無法確定(像20b3、20b4),或者是因為的成員是可選的(像20bl、20b4),或者是因 為主、副內(nèi)存池要共享(像20131、2(^2、2(^4),所以這些成員在附加部分保留內(nèi)存,并且使 用指針指向這些成員;20b 1-鎖;20b2_未初始化內(nèi)存塊鏈表,存放從一級內(nèi)存配置器中已經(jīng)分配但還沒有初始化 非易變成員的內(nèi)存塊;20b3-緩存內(nèi)存塊數(shù)組,存放緩存內(nèi)存塊(特指易變成員已經(jīng)初始化的內(nèi)存塊), 大小等于最大內(nèi)存塊的個數(shù),數(shù)組的每一個指針指向一個已經(jīng)初始化了的內(nèi)存塊地址。由 于緩存內(nèi)存塊已經(jīng)初始化,所以該內(nèi)存塊不能夠是鏈表結(jié)構(gòu),因為其沒有辦法存放一個內(nèi) 存塊結(jié)點的直接后繼或者前驅(qū)地址的指針域,所以緩存內(nèi)存塊只能使用數(shù)組存放。在使用者分配內(nèi)存塊時優(yōu)先從此數(shù)組的末尾分配,在使用者釋放內(nèi)存塊時,將內(nèi)存塊還原到初始 化狀態(tài),然后插入到此數(shù)組的末尾,這樣才保證了內(nèi)存塊只初始化一次;20b4_引用計數(shù)數(shù)組,數(shù)組里的每一個元素是其對應(yīng)的預(yù)分配內(nèi)存塊的引用計數(shù), 大小等于預(yù)分配內(nèi)存塊的個數(shù);在圖2中,一個內(nèi)存塊在其生命周期中各個階段存放的位置不同使用者創(chuàng)建內(nèi) 存池時,從一級內(nèi)存配置器中預(yù)分配的一大塊內(nèi)存23,在對齊后分割而成一塊塊原始內(nèi) 存塊2301,然后將內(nèi)存塊的起始地址作為未初始化內(nèi)存塊鏈表的后繼指針iminitiatecL list_ptr,于是原始內(nèi)存塊2301就變成了一個個鏈表元素24插入未初始化內(nèi)存塊鏈 表uninitiated_list 20b2中;未初始化內(nèi)存塊24從20b2中移出后,在對非易變成員 初始化后但沒有被使用者分配時,其變?yōu)榉且鬃兂蓡T已初始化內(nèi)存塊25緩存在CachecL blocks20b3中,因為非易變成員已初始化內(nèi)存塊25的非易變成員已經(jīng)初始化,但是內(nèi)存池 實現(xiàn)模塊不知道非易變成員在內(nèi)存塊中的確切位置,所以沒有存放后繼指針的地方,因此 通過數(shù)組存放;內(nèi)存塊從內(nèi)存池中分配后,從20b3中移出,內(nèi)存池不再對其管理,由使用者 自己管理該內(nèi)存塊;使用者使用完畢后,內(nèi)存塊被釋放后緩存在2b03中。
在圖2中,20是一個主內(nèi)存池,21是后繼內(nèi)存池,22是一個依賴于20的副內(nèi)存 池。內(nèi)存池20、21、22通過next_p00l后繼內(nèi)存池指針串成一個鏈表,組成這個鏈表是為 了系統(tǒng)管理的需要,例如查看各個內(nèi)存池的統(tǒng)計信息等。主內(nèi)存池20中的參考內(nèi)存池指 針指向副內(nèi)存池22,副內(nèi)存池22中的參考內(nèi)存池指針指向主內(nèi)存池20。主、副內(nèi)存池的 數(shù)據(jù)結(jié)構(gòu)完全一樣,但附加部分不同;主內(nèi)存池的附加部分包括鎖、未初始化內(nèi)存塊鏈表 uninitiatecLlist、緩存的內(nèi)存塊數(shù)組CachecLblocks和引用計數(shù)數(shù)組;副內(nèi)存池的附加 部分僅僅包括CachecLblocks數(shù)組。副內(nèi)存池依賴于主內(nèi)存池,共享主內(nèi)存池某些資源,即 預(yù)分配內(nèi)存塊、引用計數(shù)數(shù)組、未初始化鏈表、鎖。其預(yù)分配信息225和主內(nèi)存池的205的 各個字段都相同,都存放預(yù)分配地址塊23相關(guān)信息;副內(nèi)存池的引用計數(shù)數(shù)組指針226指 向主內(nèi)存池的20b4 ;副內(nèi)存池的uninitiated_list_ptr229指向主內(nèi)存池的20b2 ;副內(nèi)存 池的鎖指針22a指向主內(nèi)存池的20bl。除了前述共享資源外,副內(nèi)存池其余的資源是其私 有的,像統(tǒng)計信息,回調(diào)函數(shù)指針,緩存內(nèi)存塊數(shù)組。創(chuàng)建一個如圖2所示的內(nèi)存池(此處特指主內(nèi)存池)的創(chuàng)建函數(shù)流程如圖3所示, 該創(chuàng)建函數(shù)的參數(shù)有內(nèi)存池名字、內(nèi)存塊尺寸、對其方式、預(yù)分配塊數(shù)、最大可分配塊數(shù)、四 個回調(diào)函數(shù)指針、引用計數(shù)標(biāo)志和鎖標(biāo)志,創(chuàng)建步驟如下步驟301、根據(jù)參數(shù)中的鎖標(biāo)志,決定是否在附加部分中為鎖保留內(nèi)存;根據(jù)引用 計數(shù)標(biāo)志,決定是否在附加部分為引用數(shù)組保留內(nèi)存,引用數(shù)組的大小是預(yù)分配塊數(shù);緩存 內(nèi)存塊數(shù)組的大小是參數(shù)中的最大可分配塊數(shù);基于上述鎖20bl、未初始化鏈表20b2、緩 存內(nèi)存塊數(shù)組20b3和引用計數(shù)數(shù)組20b4需分配的內(nèi)存計算出附加部分的大小;步驟302、從系統(tǒng)一級內(nèi)存配置器中分配內(nèi)存用于創(chuàng)建內(nèi)存池,分配內(nèi)存的大小等 于主體部分+附加部分;步驟303、根據(jù)創(chuàng)建函數(shù)中的參數(shù)初始化該內(nèi)存池mem_p00l_t,即將步驟302中分 配的內(nèi)存塊全部清零并初始化內(nèi)存池的相關(guān)數(shù)據(jù)結(jié)構(gòu),在內(nèi)存池初始化過程中,根據(jù)鎖標(biāo) 志參數(shù),確定鎖20bl在附加部分中的地址,并對鎖進(jìn)行初始化,將鎖指針20a指向20bl ;根 據(jù)引用計數(shù)標(biāo)志參數(shù),確定引用計數(shù)數(shù)組20b4在附加部分中的地址,將207指向20b4;將208 指向 20b3 ;將 209 指向 20b2 ;步驟304、根據(jù)參數(shù)內(nèi)存塊尺寸、對齊尺寸、預(yù)分配塊數(shù)計算預(yù)分配內(nèi)存的大小。此 步驟中,首先根據(jù)對齊尺寸對內(nèi)存塊尺寸參數(shù)調(diào)整,預(yù)分配內(nèi)存的大小=調(diào)整后的內(nèi)存塊 尺寸X預(yù)分配塊數(shù)+對齊尺寸;步驟305、從系統(tǒng)中預(yù)分配大塊內(nèi)存,并填充內(nèi)存池預(yù)分配的相關(guān)信息,具體為,從 一級內(nèi)存配置器中一次性分配步驟304計算出的預(yù)分配內(nèi)存的大小的內(nèi)存單元,并填寫預(yù) 分配信息,其中2051指向一級內(nèi)存配置器返回的內(nèi)存地址,2052指向預(yù)分配內(nèi)存地址2051 對齊后的地址,2053為預(yù)分配塊數(shù)。步驟306、將預(yù)分配內(nèi)存分割成一個個內(nèi)存塊,并將這些內(nèi)存塊的起始地址初始化 為鏈表結(jié)構(gòu)插入到uninitiated_list20b2中;步驟307、按上述步驟創(chuàng)建多個內(nèi)存池并將新建的內(nèi)存池插入到上一個內(nèi)存池的 內(nèi)存池鏈表末尾,所有內(nèi)存池串成一個鏈表。步驟308、返回內(nèi)存池給用戶。
上述步驟中,創(chuàng)建內(nèi)存池的函數(shù)具有max_items和prealloc_items兩個參數(shù),其 中參數(shù)max_items表示最大可分配塊數(shù),參數(shù)prealloc_items表示預(yù)分配塊數(shù),在創(chuàng)建內(nèi) 存池時從系統(tǒng)中預(yù)分配prealloc_items個內(nèi)存塊,其不能回收,max_items減去prealloc_ items的剩余數(shù)目為動態(tài)分配的數(shù)目,不是創(chuàng)建內(nèi)存池時從系統(tǒng)中預(yù)分配的,是在內(nèi)存塊 分配函數(shù)時從系統(tǒng)中分配一個內(nèi)存塊大小的內(nèi)存,實現(xiàn)了根據(jù)需要動態(tài)擴(kuò)展,回收;如果 prealloc_items等于maxjtems,則內(nèi)存池中的所有內(nèi)存塊都是預(yù)先分配的,不可以回收; 如果preallocjtems等于零,則內(nèi)存池中的所有內(nèi)存塊都動態(tài)分配的,都是可以回收的。圖4為上述內(nèi)存池在使用時內(nèi)存塊的分配流程圖,如圖4所示,該分配過程包括以 下步驟步驟401、將內(nèi)存池分配函數(shù)的返回值設(shè)置為空;步驟402、根據(jù)內(nèi)存池鎖指針是否為空判斷是否對內(nèi)存池進(jìn)行加鎖,如果鎖指針為 非空則執(zhí)行步驟403對該內(nèi)存池進(jìn)行加鎖;步驟404、判斷內(nèi)存池中的Cached_blocks是否為空,若Cached_blocks為空則執(zhí) 行步驟405 ;否則執(zhí)行步驟412 ;步驟405、判斷內(nèi)存池中的Uninitiated_list列表是否為空,若Uninitiated_ list為空執(zhí)行步驟406 ;否則執(zhí)行步驟409 ;步驟406、判斷從一級內(nèi)存配置器里已分配的內(nèi)存塊數(shù)是否小于maxjtems,若小 于則執(zhí)行步驟407 ;否則,執(zhí)行步驟414 ;步驟407、從一級內(nèi)存配置器里分配一個內(nèi)存塊;步驟408、將分配函數(shù)的返回值指向407分配的內(nèi)存塊,執(zhí)行步驟411 ;步驟409、從uninitiated_list中移走一個內(nèi)存塊;步驟410、將分配函數(shù)的返回值指向被移走的內(nèi)存塊供用戶使用;步驟411、使用mp_init對返回值指向的內(nèi)存塊的非易變成員進(jìn)行初始化,執(zhí)行步 驟 414 ;步驟412、從CachecLblocks移走一個內(nèi)存塊;步驟413、將返回值指向被移走的內(nèi)存塊;
步驟414、判斷返回值是否為空,不為空則執(zhí)行步驟419 ;步驟415、判斷參考內(nèi)存池是否非空,不為空則執(zhí)行步驟419 ;步驟416、從參考內(nèi)存池的緩存內(nèi)存塊中移走一個內(nèi)存塊,將返回值指向被移走的 內(nèi)存塊;步驟417、判斷返回值是否為空,不為空則執(zhí)行步驟419 ;步驟418、在統(tǒng)計信息中增加統(tǒng)計和錯誤信息;步驟419、判斷返回值是否非空,該步驟為一個冗余檢查;步驟420、判斷構(gòu)造函數(shù)是否非空,不為空則執(zhí)行步驟422 ;步驟421、執(zhí)行構(gòu)造函數(shù)mp_ct0r,對易變成員進(jìn)行初始化; 步驟422、在統(tǒng)計信息中增加統(tǒng)計和錯誤信息;步驟423、判斷鎖指針是否為空,如果為非空則執(zhí)行步驟424對內(nèi)存池進(jìn)行解鎖;步驟424、返回內(nèi)存塊地址給用戶。上述步驟中,步驟402、403根據(jù)鎖指針是否為空決定是否加鎖;步驟423、424根 據(jù)鎖指針是否為空決定是否解鎖,這是實現(xiàn)互斥操作可選機(jī)制的重要步驟。步驟404、405、 406說明了分配內(nèi)存塊的優(yōu)先順序,首先是從CachecLblocks中分配,其次從uninitiatecL list中分配,接下來從一級內(nèi)存配置器中分配,最后從副內(nèi)存池的緩存內(nèi)存塊中分配。從步 驟404到步驟412、413這條分配路徑避免了內(nèi)存塊中非易變成員的初始化,是內(nèi)存塊分配 的一條最快速最優(yōu)的路徑,也是分配時調(diào)用最多的路徑,從而達(dá)到了對內(nèi)存塊分配的優(yōu)化。 步驟404到步驟405、411這條路徑比較復(fù)雜的,對內(nèi)存塊的非易變成員進(jìn)行了初始化,花費 也是很大的,但在內(nèi)存塊分配時這是調(diào)用最少的路徑,一個內(nèi)存塊在生命周期中一般只走 一次這條路徑。步驟406、407、408是實現(xiàn)動態(tài)內(nèi)存池機(jī)制重要步驟。步驟415、416是實現(xiàn) 副內(nèi)存池機(jī)制的重要步驟。圖5為內(nèi)存池中內(nèi)存塊的釋放流程圖,如圖5所示,內(nèi)存塊的釋放包括以下步驟步驟501、判斷鎖指針是否為空,如果為空則執(zhí)行步驟503 ;步驟502、對該內(nèi)存池進(jìn)行加鎖;步驟503、判斷析構(gòu)函數(shù)mp_dtor是否為非空,如為空則執(zhí)行步驟505 ;步驟504、調(diào)用析構(gòu)函數(shù)mp_dt0r,將內(nèi)存塊中的非易變成員還原到初始化狀態(tài);步驟505、將已經(jīng)銷毀的內(nèi)存塊插入到cachecLblocks的末尾;步驟506、在統(tǒng)計信息中增加統(tǒng)計信息;步驟507、判斷鎖指針是否為空,如果為非空則執(zhí)行步驟508對內(nèi)存池進(jìn)行解鎖;至此,內(nèi)存塊釋放結(jié)束。上述步驟中,步驟501、502根據(jù)鎖指針是否為空決定是否加鎖,步驟507、508根據(jù) 鎖指針是否為空決定是否解鎖,這是實現(xiàn)互斥操作可選機(jī)制重要步驟。步驟503中如果內(nèi) 存池的析構(gòu)函數(shù)非空,則執(zhí)行504內(nèi)存池的析構(gòu)函數(shù),對內(nèi)存塊中的易變成員析構(gòu),同時將 內(nèi)存塊中非易變成員保持為針對特定目標(biāo)而初始化的狀態(tài),避免了將內(nèi)存塊中非易變成員 銷毀。圖6為內(nèi)存池銷毀流程圖,如圖6所示,內(nèi)存池銷毀包括以下步驟步驟601、判斷鎖指針是否為空,如果為空則執(zhí)行步驟603 ;步驟602、執(zhí)行加鎖操作;
步驟603、判斷mp_fini是否非空,不為空則執(zhí)行步驟608 ;步驟604、判斷cached_blocks列表是否非空,不為空則執(zhí)行步驟608 ;步驟605、對其中的每一個內(nèi)存塊執(zhí)行mp_fini銷毀非易變成員;步驟606、將其中的每一個內(nèi)存塊從cached_blocks中移走;步驟607、將其中的每一個內(nèi)存塊加入到uninitiated_list中;步驟608、判斷參考內(nèi)存池是否為空,不為空則執(zhí)行步驟621 ;步驟609、判斷uninitiated_list是否非空,不為空則執(zhí)行步驟612 ;步驟610、判斷該內(nèi)存塊是否為非預(yù)分配的,不是則執(zhí)行步驟612 ; 步驟611、將該內(nèi)存塊從iminitiatecLlist中移走,并將其釋放回一級內(nèi)存配置 器中,返回步驟609;步驟612、判斷預(yù)分配的內(nèi)存塊是否為非空,不為空則執(zhí)行步驟614;步驟613,將預(yù)分配內(nèi)存釋放回一級內(nèi)存配置器中;步驟614、判斷鎖指針是否為空,如果為空則執(zhí)行步驟616 ;步驟615、執(zhí)行解鎖操作;步驟616、關(guān)中斷;步驟617、判斷是否鎖指針非空,否則執(zhí)行步驟619 ;步驟618、對鎖進(jìn)行銷毀;步驟619、從內(nèi)存池鏈表中移出該內(nèi)存池;步驟620、將內(nèi)存池釋放回一級內(nèi)存配置器中;步驟621、開中斷,返回;步驟621、將參考內(nèi)存池的參考內(nèi)存池指針置為空;步驟622、關(guān)中斷;步驟623、從內(nèi)存池鏈表中移出該內(nèi)存池;步驟624、將內(nèi)存池釋放回一級內(nèi)存配置器中;步驟625、開中斷,返回。至此,內(nèi)存池銷毀。上述步驟中,步驟601、602和步驟614、615根據(jù)鎖指針是否為空決定是否對內(nèi)存 池加鎖和解鎖,所以說對內(nèi)存池的某些部分的銷毀是在鎖的保護(hù)下執(zhí)行的。步驟603中,如 果mp_fini非空,則執(zhí)行604、605、606、607,對每一內(nèi)存塊執(zhí)行mp_fini,從緩存集合中移 出,插入到iminitiatecLlist中。步驟608根據(jù)副內(nèi)存池是否非空來決定是否銷毀主、副 內(nèi)存池中共享的某些成員。圖7為副內(nèi)存池創(chuàng)建函數(shù)流程圖,其參數(shù)有內(nèi)存池名字、四個回調(diào)函數(shù)指針、指向 主內(nèi)存池的指針。如圖7所示,副內(nèi)存池的創(chuàng)建包括以下步驟步驟701、計算副內(nèi)存池附加部分的大小,副內(nèi)存池的附加部分中只有cachecL blockes 數(shù)組;步驟702、從一級內(nèi)存配置器中為副內(nèi)存池分配一塊內(nèi)存,用于創(chuàng)建副內(nèi)存池;步驟703、對副內(nèi)存池不需要互斥的部分進(jìn)行初始化,包括統(tǒng)計信息、四個回調(diào)函 數(shù)指針;步驟704、判斷主內(nèi)存池中的鎖指針是否為空,如果為空則執(zhí)行步驟706 ;否則執(zhí)行步驟705對主內(nèi)存池進(jìn)行加鎖;副內(nèi)存池與主內(nèi)存池共享一些資源,鎖就是共享資源,主 內(nèi)存池使用了鎖,副內(nèi)存池就必須使用,應(yīng)用計數(shù)也是如此,所以創(chuàng)建函數(shù)里沒有創(chuàng)建主內(nèi) 存池的函數(shù)所具有的鎖和應(yīng)用計數(shù)標(biāo)志參數(shù)。步驟706、將主、副內(nèi)存池的參考內(nèi)存池指針互相指向;步驟707、將副內(nèi)存池的一些字段指向主內(nèi)存池的相應(yīng)共享字段,如CachecL blocks CachecLnums、預(yù)分配信息、鎖、引用計數(shù)數(shù)組、未初始化鏈表;步驟708、判斷主內(nèi)存池中的鎖指針是否為空,如果為非空則執(zhí)行步驟709對主內(nèi) 存池進(jìn)行解鎖;否則執(zhí)行步驟710 ;步驟710、返回內(nèi)存池給使用者。主內(nèi)存池20中的參考內(nèi)存池指針指向副內(nèi)存池22,副內(nèi)存池22中的參考內(nèi)存池 指針指向主內(nèi)存池20,因此二者互為參考內(nèi)存池。圖8為從參考內(nèi)存池中借用內(nèi)存塊流程圖,如圖8所示,包括以下步驟 步驟801、判斷從參考內(nèi)存池中借用內(nèi)存塊的參數(shù)是否有效,當(dāng)參數(shù)無效時退出; 有效時執(zhí)行步驟802 ;步驟802、從參考內(nèi)存池的cached_blocks中移出一個內(nèi)存塊;步驟803、判斷參考內(nèi)存池的mp_fini是否為非空,如果參考內(nèi)存池的mp_fini非 空,則執(zhí)行步驟804對該內(nèi)存塊執(zhí)行mp_fini,銷毀內(nèi)存塊中的非易變成員變量,否則,執(zhí)行 步驟805 ;步驟805、判斷該內(nèi)存池的mp_init是否為非空,如果mp_init為非空,則執(zhí)行步驟 806對該內(nèi)存塊執(zhí)行mp_init,初始化內(nèi)存塊非易變成員變量,執(zhí)行步驟807 ;步驟807、返回該內(nèi)存塊供用戶使用。例如,副內(nèi)存池共享主內(nèi)存池的內(nèi)存塊資源,副內(nèi)存池創(chuàng)建時未預(yù)分配內(nèi)存塊。當(dāng) 使用者從副內(nèi)存池中第一次分配內(nèi)存塊時,(1)首先其緩存內(nèi)存塊為零,不能分配;(2)從 其未初始化鏈表中分配,但該鏈表指針是指向主內(nèi)存池未初始化鏈表;(3)如果主內(nèi)存池 未初始化鏈表也為空無法分配,再判斷是否可以從一級內(nèi)存配置器中(已分配塊數(shù)是否達(dá) 到maxjtems)分配,如果可以就從一級內(nèi)存配置器中分配;(4)還是沒有分配到內(nèi)存塊,就 借用主內(nèi)存池中緩存的內(nèi)存塊(因為緩存的是非易變成員已經(jīng)初始化了的對象,現(xiàn)在借用 就要銷毀非易變成員,所以放在最后)。當(dāng)使用者使用完了后,就將其釋放到副內(nèi)存池的緩 存數(shù)組里,使用者再從副內(nèi)存池分配時,就可以從其緩存的數(shù)組中分配。副內(nèi)存池可以借用 主內(nèi)存池的緩存內(nèi)存塊,反之主內(nèi)存池也可以借用副內(nèi)存池的緩存內(nèi)存塊。圖9為本發(fā)明實現(xiàn)內(nèi)存塊引用計數(shù)查找的流程圖,如圖9所示,包括以下步驟步驟901、將引用計數(shù)地址的返回值設(shè)為空;步驟902、判斷內(nèi)存池中的鎖指針是否為空,如果為非空則執(zhí)行步驟903進(jìn)行加 鎖;否則執(zhí)行步驟904 ;步驟904、判斷該內(nèi)存塊是否為預(yù)分配的,如果是預(yù)分配的,則執(zhí)行步驟905;否則 執(zhí)行步驟907 ;步驟905、根據(jù)內(nèi)存塊相對于預(yù)分配內(nèi)存塊基線地址2052的偏移以及內(nèi)存塊的大 小,計算出引用計數(shù)數(shù)組的索引號;步驟906、返回該索引號對應(yīng)的引用計數(shù)數(shù)組的地址,執(zhí)行步驟908 ;
步驟907、設(shè)置內(nèi)存塊的引用計數(shù)地址為該內(nèi)存塊的末尾四字節(jié)地址;步驟908、判斷內(nèi)存池中的鎖指針是否為空,如果為非空則執(zhí)行步驟909進(jìn)行解 鎖;否則執(zhí)行步驟910;步驟910、返回引用計數(shù)的地址。綜上所述,本發(fā)明具有以下優(yōu)點 (1)、本發(fā)明提出了非易變成員和易變成員的概念,對非易變成員的初始化和銷毀 進(jìn)行了優(yōu)化,從內(nèi)存池中分配內(nèi)存塊時,按照本身緩存的內(nèi)存、未初始化鏈表對應(yīng)的內(nèi)存, 一級內(nèi)存配置器中的動態(tài)內(nèi)存的優(yōu)先次序進(jìn)行分配,如果還沒有分配到內(nèi)存塊,就從副內(nèi) 存池的緩存內(nèi)存塊中借用一塊,先對其執(zhí)行終結(jié)函數(shù)mp_fini,再對其初始化非易變成員后 返回給使用者。其中,步驟101 — 102 — 105是內(nèi)存塊分配時調(diào)用最多的路徑,也是一條最 優(yōu)最快速的路徑;步驟101 — 103 — 104 — 105中,步驟104對非易變成員的初始化會消耗 大量資源,本專利保證了這條路徑是一條分配時調(diào)用很少的路徑;步驟107 — 108是內(nèi)存 塊釋放時調(diào)用路徑,本專利對此路徑進(jìn)行優(yōu)化沒有對非易變成員進(jìn)行銷毀,在調(diào)用最多的 路徑上不會出現(xiàn)對非易變成員的初始化和銷毀。內(nèi)存塊中非易變成員只在第一次分配時由 內(nèi)存池調(diào)用mp_init進(jìn)行一次初始化,內(nèi)存塊釋放到內(nèi)存池時不執(zhí)行非易變成員的銷毀, 非易變成員只是在其釋放到一級配置器時執(zhí)行銷毀或者在主、副內(nèi)存池借用內(nèi)存塊時調(diào)用 mp_fini對非易變成員銷毀。在內(nèi)存塊釋放到內(nèi)存池時,一般通過調(diào)用內(nèi)存塊析構(gòu)函數(shù)mp_ dtor,將內(nèi)存塊中非易變成員保持為針對特定目而初始化的狀態(tài),插入到內(nèi)存池中緩存鏈 表中,后續(xù)的內(nèi)存塊分配不需要執(zhí)行初始化函數(shù),因為從上次釋放和調(diào)用析構(gòu)之后,它已經(jīng) 處于所需的初始化狀態(tài)中了。易變成員在內(nèi)存塊每次分配時都調(diào)用mp_ctor進(jìn)行初始化, 在內(nèi)存塊每次釋放時,調(diào)用mp_dt0r執(zhí)行其銷毀過程。在內(nèi)存塊的歷次使用之間,保持內(nèi)存 塊中非易變成員的初始化狀態(tài),這樣在每次使用內(nèi)存塊時,這些非易變成員就不需要銷毀 和重新創(chuàng)建。例如,一個包含一個互斥鎖的內(nèi)存塊僅僅需要在內(nèi)存塊第一次被分配時執(zhí)行 一次互斥鎖的初始化,該內(nèi)存塊之后可以被釋放和重分配無數(shù)次而不必每次承受互斥鎖銷 毀和初始化的開銷。從而大大提高了內(nèi)存池分配和釋放內(nèi)存塊的效率。本發(fā)明通過內(nèi)存池 的引用計數(shù)、副內(nèi)存池機(jī)制避免了數(shù)據(jù)的無益拷貝,從而提高了系統(tǒng)效率。(2)、本發(fā)明實現(xiàn)了副內(nèi)存池機(jī)制。副內(nèi)存池創(chuàng)建時綁定的內(nèi)存池就是主內(nèi)存池。 主、副內(nèi)存池相似,分配內(nèi)存塊、釋放內(nèi)存塊、銷毀內(nèi)存池函數(shù)都是一樣的,只是主、副內(nèi)存 池的創(chuàng)建函數(shù)不同。副內(nèi)存池依賴于主內(nèi)存池。主內(nèi)存池必須先于副內(nèi)存池創(chuàng)建,副內(nèi)存 池的銷毀先于主內(nèi)存池的銷毀,這些順序由使用者保證。副內(nèi)存池綁定主內(nèi)存池,其共享主 內(nèi)存池的未初始化內(nèi)存塊鏈表、鎖、引用計數(shù)數(shù)組。主、副內(nèi)存池互為參考內(nèi)存池。從對象 的角度來講,主、副內(nèi)存池緩存具有相同數(shù)據(jù)結(jié)構(gòu)的兩種不同對象(屬性不同),從一個參 考內(nèi)存池分配的對象,在使用過程中可以改變屬性變成另一種對象,使用完畢后被釋放到 另一個參考內(nèi)存池中,作為另一種對象緩存;并且一個內(nèi)存池中如果沒有可以分配的對象 了,它可以從其參考內(nèi)存池借用其緩存的對象,將該借用對象改變屬性后賦予新的屬性,以 作為一種新的對象供分配。(3)、實現(xiàn)了內(nèi)存塊的引用計數(shù)。內(nèi)存池的數(shù)據(jù)結(jié)構(gòu)中具有引用計數(shù)數(shù)組,在創(chuàng)建 時為預(yù)分配的內(nèi)存塊分配該數(shù)組,數(shù)組大小是預(yù)分配內(nèi)存塊的個數(shù),用于存放每一個預(yù)分 配內(nèi)存塊的引用計數(shù);動態(tài)分配的內(nèi)存塊,在分配內(nèi)存時,末尾額外多分配四個字節(jié)的內(nèi)
14存,用于引用計數(shù);在查找一個內(nèi)存塊的引用計數(shù)時,如果其地址落在預(yù)分配的內(nèi)存地址范 圍內(nèi),則根據(jù)其相對于預(yù)分配內(nèi)存地址偏移得到引用計數(shù)數(shù)組的索引號,從而得到該內(nèi)存 塊的引用計數(shù);如果內(nèi)存塊是動態(tài)分配的,其引用計數(shù)就是該內(nèi)存塊末尾多分配的四個字 節(jié)。(4)、實現(xiàn)了鎖的可選。內(nèi)存池的數(shù)據(jù)結(jié)構(gòu)中具有鎖和指向該鎖的鎖指針,在分配 和釋放內(nèi)存塊時根據(jù)鎖指針是否非空對內(nèi)存池進(jìn)行加鎖或解鎖,從而實現(xiàn)了鎖的可選。(5)、實現(xiàn)了內(nèi)存池從系統(tǒng)中預(yù)分配內(nèi)存和從系統(tǒng)中動態(tài)分配內(nèi)存兩種方案。創(chuàng) 建內(nèi)存池的函數(shù)有max_items和prealloc_items兩個參數(shù),其中參數(shù)max_items表示最 大可分配塊數(shù);參數(shù)preallocjtems表示預(yù)分配塊數(shù),在創(chuàng)建內(nèi)存池時從系統(tǒng)中預(yù)分配 prealloc_items個內(nèi)存塊,其不能回收;max_items減去prealloc_items的剩余數(shù)目,是 動態(tài)分配的,不是創(chuàng)建內(nèi)存池時從系統(tǒng)中預(yù)分配的,是在內(nèi)存塊分配函數(shù)時從系統(tǒng)中分配 一個內(nèi)存塊大小的內(nèi)存,實現(xiàn)了根據(jù)需要動態(tài)擴(kuò)展,回收。如果preallocjtems等于maX_ items,則內(nèi)存池中的所有內(nèi)存塊都是預(yù)先分配的,不可以回收;如果preallocjtems等于 零,則內(nèi)存池中的所有內(nèi)存塊都動態(tài)分配的,都是可以回收的。本發(fā)明不局限于上述最佳實施方式,任何人應(yīng)該得知在本發(fā)明的啟示下作出的結(jié) 構(gòu)變化,凡是與本發(fā)明具有相同或相近的技術(shù)方案,均落入本發(fā)明的保護(hù)范圍之內(nèi)。
1權(quán)利要求
嵌入式系統(tǒng)高效內(nèi)存池的實現(xiàn)方法,該內(nèi)存池中的每個內(nèi)存塊的生命周期包括分配、使用和釋放三個階段,其特征在于內(nèi)存塊的分配階段包括以下步驟步驟101、判斷內(nèi)存池中是否存在已經(jīng)初始化了的緩存內(nèi)存塊,如果存在則執(zhí)行步驟102,否則執(zhí)行步驟103;步驟102、從上述緩存內(nèi)存塊中分配內(nèi)存塊供非易變成員使用,然后轉(zhuǎn)至步驟105;步驟103、從內(nèi)存池未初始化內(nèi)存塊鏈表中分配一個未初始化的內(nèi)存塊;步驟104、初始化內(nèi)存塊供易變成員使用;步驟105、構(gòu)造內(nèi)存塊,并初始化;內(nèi)存塊的釋放階段包括以下步驟步驟107、使非易變成員占用的內(nèi)存塊的回歸到初始化狀態(tài);步驟108、將內(nèi)存塊釋放到內(nèi)存池中。
2.如權(quán)利要求1所述的嵌入式系統(tǒng)高效內(nèi)存池的實現(xiàn)方法,其特征在于內(nèi)存池的數(shù)據(jù) 結(jié)構(gòu)中保存了內(nèi)存池創(chuàng)建函數(shù)的四個回調(diào)函數(shù)指針,非易變成員初始化函數(shù)mp_init、非易 變成員終結(jié)函數(shù)mp_f ini、構(gòu)造函數(shù)mp_ctor和析構(gòu)函數(shù)mp_dt0r指針,非易變成員的初始 化通過調(diào)用mp_init實現(xiàn),其銷毀通過調(diào)用mp_fini實現(xiàn);易變成員初始化通過調(diào)用mp_ ctor實現(xiàn),其銷毀通過調(diào)用mp_dtor實現(xiàn)。
3.如權(quán)利要求1所述的嵌入式系統(tǒng)高效內(nèi)存池的實現(xiàn)方法,其特征在于內(nèi)存池的數(shù)據(jù) 結(jié)構(gòu)中具有鎖和指向該鎖的鎖指針,在分配和釋放內(nèi)存塊時根據(jù)鎖指針是否非空對內(nèi)存池 進(jìn)行加鎖或解鎖。
4.如權(quán)利要求1所述的嵌入式系統(tǒng)高效內(nèi)存池的實現(xiàn)方法,其特征在于創(chuàng)建內(nèi)存池的 函數(shù)具有max_iterns禾口 prealloc_items兩個參數(shù),其中參數(shù)max_iterns表示最大可分配 塊數(shù),參數(shù)prealloc_items表示預(yù)分配塊數(shù),在創(chuàng)建內(nèi)存池時從系統(tǒng)中預(yù)分配prealloc_ items個內(nèi)存塊,該內(nèi)存塊不能回收;max_items減去prealloc_items的剩余數(shù)目為動態(tài)分 配的數(shù)目,該內(nèi)存塊可以回收。
5.如權(quán)利要求1所述的嵌入式系統(tǒng)高效內(nèi)存池的實現(xiàn)方法,其特征在于內(nèi)存池的數(shù)據(jù) 結(jié)構(gòu)中具有引用計數(shù)數(shù)組,用于在創(chuàng)建內(nèi)存池時分配預(yù)分配的內(nèi)存塊,數(shù)組大小是預(yù)分配 內(nèi)存塊的個數(shù),用于存放每一個預(yù)分配內(nèi)存塊的引用計數(shù);動態(tài)分配的內(nèi)存塊,在分配內(nèi)存 時,末尾額外多分配四個字節(jié)的內(nèi)存,用于引用計數(shù);在查找一個內(nèi)存塊的引用計數(shù)時,如 果其地址落在預(yù)分配的內(nèi)存地址范圍內(nèi),則根據(jù)其相對于預(yù)分配內(nèi)存地址偏移得到引用計 數(shù)數(shù)組的索引號,從而得到該內(nèi)存塊的引用計數(shù);如果內(nèi)存塊是動態(tài)分配的,其引用計數(shù)就 是該內(nèi)存塊末尾多分配的四個字節(jié)。
6.如權(quán)利要求1至5項任一項權(quán)利要求所述的嵌入式系統(tǒng)高效內(nèi)存池的實現(xiàn)方法,其 特征在于內(nèi)存池包括主、副內(nèi)存池,二者具有相同的數(shù)據(jù)結(jié)構(gòu)且通過參考內(nèi)存池指針相互 指引。
7.如權(quán)利要求6所述的嵌入式系統(tǒng)高效內(nèi)存池的實現(xiàn)方法,其特征在于內(nèi)存塊的分配 次序為,首先從內(nèi)存池的緩存內(nèi)存塊分配,其次從未初始化內(nèi)存塊鏈表中分配,接下來從一 級內(nèi)存配置器中分配,最后從參考內(nèi)存池的緩存內(nèi)存塊中分配。
全文摘要
本發(fā)明公開了一種嵌入式系統(tǒng)高效內(nèi)存池的實現(xiàn)方法,內(nèi)存塊中非易變成員只在第一次分配或者在主、副內(nèi)存池之間借用內(nèi)存塊時由內(nèi)存池調(diào)用mp_init進(jìn)行一次初始化,內(nèi)存塊釋放到內(nèi)存池時不執(zhí)行非易變成員的銷毀,非易變成員只是在其釋放到一級配置器時執(zhí)行銷毀或者在主、副內(nèi)存池之間借用內(nèi)存塊時調(diào)用mp_fini對非易變成員銷毀。在內(nèi)存塊釋放到內(nèi)存池,通過調(diào)用內(nèi)存塊析構(gòu)函數(shù)mp_dtor,將內(nèi)存塊中非易變成員保持為針對特定目而初始化的狀態(tài),插入到內(nèi)存池中緩存鏈表中,后續(xù)的內(nèi)存塊分配不需要執(zhí)行初始化函數(shù)。這樣在每次使用內(nèi)存塊時,這些非易變成員就不需要銷毀和重新創(chuàng)建,從而大大提高了內(nèi)存池的分配和釋放內(nèi)存塊的效率。
文檔編號G06F12/02GK101968772SQ201010515419
公開日2011年2月9日 申請日期2010年10月22日 優(yōu)先權(quán)日2010年10月22日
發(fā)明者付華楷, 張峰, 李寧, 胡小波, 馬紅斌 申請人:烽火通信科技股份有限公司