一種面向非固定包長的無鎖化多鏈內(nèi)存管理方法
【專利摘要】本發(fā)明針對定長內(nèi)存池中內(nèi)存使用率偏低、不能動態(tài)調(diào)整內(nèi)存池大小及其他內(nèi)存管理方案不能很好的預(yù)防突發(fā)流量造成的內(nèi)存抖動的問題,提出了一種面向非固定包長的無鎖化多鏈內(nèi)存管理方法。首先初始化動態(tài)可伸縮內(nèi)存池,即程序初始化兩個內(nèi)存池管理數(shù)組,一個為快鏈的管理數(shù)組,另一個為滿鏈和非滿鏈的管理數(shù)組;然后初始化三個數(shù)組中指向可分配內(nèi)存的指針為NULL;其次向申請內(nèi)存的線程或進(jìn)程提供相應(yīng)的內(nèi)存;最后回收線程或進(jìn)程使用完的內(nèi)存。
【專利說明】
一種面向非固定包長的無鎖化多鏈內(nèi)存管理方法
技術(shù)領(lǐng)域
[0001]本發(fā)明屬于內(nèi)存管理領(lǐng)域,涉及一種面向非固定包長的無鎖化多鏈內(nèi)存管理方法。
【背景技術(shù)】
[0002]現(xiàn)在通用的內(nèi)存管理模型,一般分為兩類:一類是定長內(nèi)存池;另一類是Linux常用的內(nèi)存管理模型DLMal 1c、PTMal 1c等。
[0003]現(xiàn)實項目中,開發(fā)人員為了節(jié)省程序大量Malloc/free的時間消耗,通常采用定長內(nèi)存池,即在程序初始化時,直接向操作系統(tǒng)申請一大塊內(nèi)存,并把該內(nèi)存按照程序要求的固定長度劃分為更小的內(nèi)存塊,然后把這些內(nèi)存塊用鏈表進(jìn)行管理。這樣程序進(jìn)行申請和釋放內(nèi)存操作時,實際上是從該內(nèi)存池的空閑鏈中申請和釋放內(nèi)存塊,其時間復(fù)雜度可以達(dá)到0(1)。雖然在時間效率上有很好的表現(xiàn),但是定長內(nèi)存池有兩個明顯的缺陷。一個是因為初始化時已經(jīng)定義好了固定長度的內(nèi)存塊,所以不論用戶申請多大的內(nèi)存塊,該內(nèi)存池總是分配給它一個固定塊大小的內(nèi)存,有時這樣的內(nèi)存分配會使得內(nèi)存池中內(nèi)存的平均使用率偏低;另一個是,一般程序在初始化時會申請多個空閑內(nèi)存鏈,每個內(nèi)存鏈中掛在了相同大小的內(nèi)存塊,不同內(nèi)存鏈中內(nèi)存塊大小不同,所有內(nèi)存鏈集中用數(shù)組進(jìn)行管理。由于開發(fā)人員不能預(yù)估到哪個大小的內(nèi)存塊常用,哪個不常用。所以為了系統(tǒng)的健壯性,通常會讓每條空閑內(nèi)存鏈中的空閑塊數(shù)量相同。這樣也會造成內(nèi)存的浪費。
[0004]另一方面對于Linux系統(tǒng)常用的內(nèi)存管理模型DLMalloc、PTMalloc、TCMalloc來說,由于它們是操作系統(tǒng)的一種內(nèi)存管理方案,開發(fā)者在進(jìn)行開發(fā)時,為了考慮到系統(tǒng)的健壯性,其相對的管理方案會設(shè)計的比較復(fù)雜,不能直接用到一些應(yīng)用層設(shè)備上。并且此類模型中,當(dāng)遇到突發(fā)流量內(nèi)存管理模型無法滿足用戶需求時,通常會向操作系統(tǒng)申請內(nèi)存然后再分配給用戶,而當(dāng)用戶使用完成后,在交還給操作系統(tǒng)。下次再有突發(fā)流量時,仍然按照上述步驟操作,這樣做容易照成內(nèi)存抖動惡化。
【發(fā)明內(nèi)容】
[0005]本發(fā)明針對定長內(nèi)存池中內(nèi)存使用率偏低、不能動態(tài)調(diào)整內(nèi)存池大小及其他內(nèi)存管理方案不能很好的預(yù)防突發(fā)流量造成的內(nèi)存抖動的問題,提出了一種面向非固定包長的無鎖化多鏈內(nèi)存管理方法。
[0006]本發(fā)明通過以下技術(shù)方案解決上述技術(shù)問題。
[0007]—種面向非固定包長的無鎖化多鏈內(nèi)存管理方法,首先初始化動態(tài)可伸縮內(nèi)存池,即程序初始化兩個內(nèi)存池管理數(shù)組,一個為快鏈的管理數(shù)組,另一個為滿鏈和非滿鏈的管理數(shù)組;然后初始化三個數(shù)組中指向可分配內(nèi)存的指針為NULL;其次向申請內(nèi)存的線程或進(jìn)程提供相應(yīng)的內(nèi)存;最后回收線程或進(jìn)程使用完的內(nèi)存。
[0008]所述向申請內(nèi)存的線程或進(jìn)程提供相應(yīng)的內(nèi)存,具體采用下列步驟:
[0009]步驟21:當(dāng)用戶申請內(nèi)存時,比較用戶申請的內(nèi)存是否大于4k,如果是則執(zhí)行步驟29,否則執(zhí)行步驟22;
[0010]步驟22:計算出用戶申請的內(nèi)存相應(yīng)的級數(shù),定位到第一層中管理數(shù)組相應(yīng)位置,查看該位置處未滿鏈?zhǔn)欠駷榭眨绻麨榭請?zhí)行步驟25,否則執(zhí)行步驟23;
[0011]步驟23:從該未滿鏈中的第一個區(qū)段的空閑鏈中拿出空閑內(nèi)存塊分配給用戶使用,并把該內(nèi)存塊的頭部字段標(biāo)志位由空閑改為等差,并且修改區(qū)段中空閑鏈表,把該區(qū)段中的占用計數(shù)TEAM結(jié)構(gòu)體中的單元占用加I ;
[0012]步驟24:查看步驟23中分配區(qū)段的空閑鏈?zhǔn)欠駷榭眨绻麨榭?,則把該區(qū)段以尾插法鏈入到相應(yīng)級別的滿鏈中,否者結(jié)束;
[0013]步驟25:如果未滿鏈為空,則需要擴充區(qū)段;首先申請加鎖,然后查看快鏈的管理數(shù)組中相應(yīng)級數(shù)的快鏈?zhǔn)欠駷榭眨绻粸榭談t執(zhí)行步驟26;如果為空,則執(zhí)行步驟27;
[0014]步驟26:從該快鏈中取出一個區(qū)段放入到第一層數(shù)組中,然后枚舉單元,并把該區(qū)段進(jìn)行掛接,然后解鎖,累加該區(qū)段所在鏈表頭部字段;
[0015]步驟27:計算實際分配長度,然后進(jìn)行申請并判斷是否成功,如果成功,則執(zhí)行步驟28,否者返回-1;
[0016]步驟28:按照對應(yīng)級數(shù)相應(yīng)的區(qū)段大小申請一塊內(nèi)存,并把該內(nèi)存劃分為小的內(nèi)存塊,標(biāo)注內(nèi)存塊頭部字段為空閑,整理空閑鏈,最后把該區(qū)段鏈入到第一層的未滿鏈中,然后分配給用戶需要使用的內(nèi)存;
[0017]步驟29:直接malloc從系統(tǒng)中申請,申請成功后,標(biāo)記內(nèi)存塊頭部字段為系統(tǒng),并返回給用戶使用,否則,返回-1。
[0018]所述回收線程或進(jìn)程使用完的內(nèi)存,具體采用下列步驟:
[0019]步驟31:當(dāng)用戶釋放其使用的內(nèi)存時,首先根據(jù)需要釋放的內(nèi)存找到內(nèi)存塊的首地址;
[0020]步驟32:根據(jù)內(nèi)存塊頭部中類型標(biāo)記是否為0x02,如果不是從內(nèi)存池中申請得到的,則執(zhí)行步驟33,否者執(zhí)行步驟38;
[0021]步驟33:根據(jù)內(nèi)存塊頭部結(jié)構(gòu)體中的區(qū)號計算該區(qū)段的首地址,然后修改該區(qū)段的空閑鏈和占用計數(shù);判斷該區(qū)段的空閑鏈?zhǔn)欠駷榭?,若為空則執(zhí)行步驟34,否者執(zhí)行步驟35;
[0022]步驟34:如果該區(qū)段的空閑鏈為空,則把該區(qū)段從滿鏈中摘除并把該區(qū)段從尾部鏈入到非滿鏈中;
[0023]步驟35:如果該區(qū)段的空閑鏈非空,則歸還內(nèi)存塊,并修改內(nèi)存塊類型字段及區(qū)段和總結(jié)構(gòu)體中變量,然后是Held減I;最后判斷區(qū)段占用計數(shù)是否為0,若為0,則執(zhí)行步驟36,否則表示釋放內(nèi)存完成;
[0024]步驟36:如果占用計數(shù)為0,則說明該區(qū)段所有內(nèi)存塊全部未使用,這時需要把該區(qū)段從未滿鏈中摘除掉,然后執(zhí)行步驟37;
[0025]步驟37:從未滿鏈摘除以后,與衰減因子進(jìn)行比較,如果滿足衰減因子,則把該區(qū)段是返還給操作系統(tǒng),如果不滿足衰減因子,則直接把該區(qū)段放入到快鏈管理數(shù)組相對應(yīng)級別中的快鏈中;
[0026]步驟38:該內(nèi)存塊的內(nèi)存標(biāo)簽為系統(tǒng),直接把該內(nèi)存塊返還給操作系統(tǒng)。
[0027]本發(fā)明的有益效果:
[0028]1、本發(fā)明可以根據(jù)程序申請內(nèi)存情況動態(tài)調(diào)整內(nèi)存池相應(yīng)內(nèi)存塊的數(shù)量;其次,內(nèi)存池分為第一層、第二層,可以大大減少加、解鎖造成的系統(tǒng)資源浪費;最后,第二層中的快鏈作為操作系統(tǒng)和第一層之間的緩沖區(qū),可以有效解決突發(fā)流量造成的內(nèi)存抖動情況。
[0029]2、本發(fā)明中一方面提高了內(nèi)存使用率,并可以動態(tài)調(diào)整內(nèi)存池中不同級別內(nèi)存塊對應(yīng)的區(qū)塊的數(shù)量。另一方面隨著申請內(nèi)存塊的大小變大時,使用DS-MP算法內(nèi)存池管理內(nèi)存,除了第一次消耗的時間增加的較大外,以后消耗的時間增加成本較為理想。
【附圖說明】
[0030]圖1為本發(fā)明面向非固定包長的無鎖化多鏈內(nèi)存管理方法流程圖;
[0031 ]圖2為本發(fā)明DS-MP算法中分配算法流程圖;
[0032]圖3為本發(fā)明DS-MP算法中回收算法流程圖。
【具體實施方式】
[0033]下面結(jié)合具體實施例對本發(fā)明作更詳細(xì)的描述:
[0034](I)實驗環(huán)境
[0035]本實驗是在I inux 64位操作系統(tǒng),2.6.32內(nèi)核版本,24核CPU數(shù),頻率為1200MHz,16G內(nèi)存,gcc版本為4.4.5的服務(wù)器上進(jìn)行。
[0036]本發(fā)明進(jìn)行了兩個模擬實驗,第一個實驗主要對比DS-MP算法的內(nèi)存池和定長內(nèi)存池的內(nèi)存使用率;第二個實驗主要對比Mal loc/f ree、PTMal 1c、DS-MP算法內(nèi)存池中分配和回收內(nèi)存的時間效率。
[0037]第一個模擬實驗,首先初始化128字節(jié)、512字節(jié)、1024字節(jié)三個固定長度的內(nèi)存池,然后使用程序隨機申請不大于1024字節(jié)的內(nèi)存1000次,統(tǒng)計每次申請內(nèi)存后內(nèi)存使用率,最后計算使用三個固定長度的內(nèi)存池和DS-MP算法的內(nèi)存池之間的內(nèi)存平均使用率。在DS-MP算法中,由于第一層中數(shù)組索引為等差數(shù)列,且等差值為32字節(jié)。所以,當(dāng)程序隨機申請內(nèi)存時,內(nèi)存最大浪費值為31字節(jié)。而在固定內(nèi)存池中,對于系統(tǒng)隨機申請的內(nèi)存,內(nèi)存池一般把最靠近該內(nèi)存大小并且大于等于該內(nèi)存的內(nèi)存塊分配給系統(tǒng)。比如申請129字節(jié),則浪費383字節(jié)。
[0038]第二個模擬實驗,首先使用mal 1c、tcmal 1c、DS_MP算法三種算法去申請3個不同大小的內(nèi)存塊,每次申請100塊,總共申請20輪次,然后記錄所有輪次申請和釋放內(nèi)存消耗的系統(tǒng)時間,并進(jìn)行對比。
[0039](2)實驗結(jié)果和分析
[0040]在本發(fā)明中,作者使用DS-MP算法來管理內(nèi)存,使得程序在分配、釋放內(nèi)存時的時間消耗減小。主要從兩個方面對比了 DS-MP算法的高效性,一方面著重對比了使用定長內(nèi)存池和DS-MP算法的內(nèi)存池進(jìn)行內(nèi)存分配時的內(nèi)存使用率情況,從數(shù)據(jù)上我們可以看到使用DS-MP算法的內(nèi)存池內(nèi)存使用率比使用定長內(nèi)存池內(nèi)存使用率高20%左右。另一方面著重對比了程序程序使用Mal 1c、PTMal 1c、DS-MP算法申請相同大小的內(nèi)存塊時的時間消耗。其中當(dāng)我們申請的內(nèi)存塊小于26字節(jié)時,PTMalloc的時間消耗最少。通過數(shù)據(jù)對比我們可以看到,當(dāng)申請260字節(jié)、2600字節(jié)時,使用DS-MP算法的內(nèi)存池管理內(nèi)存消耗的時間遠(yuǎn)遠(yuǎn)小于其他兩種方法消耗的時間。而且隨著申請內(nèi)存塊的大小變大時,除了第一次消耗的時間增加的較大外,以后消耗的時間增加成本較為理想。
【主權(quán)項】
1.一種面向非固定包長的無鎖化多鏈內(nèi)存管理方法,其特征在于:首先初始化動態(tài)可伸縮內(nèi)存池,即程序初始化兩個內(nèi)存池管理數(shù)組,一個為快鏈的管理數(shù)組,另一個為滿鏈和非滿鏈的管理數(shù)組;然后初始化三個數(shù)組中指向可分配內(nèi)存的指針為NULL;其次向申請內(nèi)存的線程或進(jìn)程提供相應(yīng)的內(nèi)存;最后回收線程或進(jìn)程使用完的內(nèi)存。2.如權(quán)利要求1所述的一種面向非固定包長的無鎖化多鏈內(nèi)存管理方法,其特征在于:所述向申請內(nèi)存的線程或進(jìn)程提供相應(yīng)的內(nèi)存,具體采用下列步驟: 步驟21:當(dāng)用戶申請內(nèi)存時,比較用戶申請的內(nèi)存是否大于4k,如果是則執(zhí)行步驟29,否則執(zhí)行步驟22; 步驟22:計算出用戶申請的內(nèi)存相應(yīng)的級數(shù),定位到第一層中管理數(shù)組相應(yīng)位置,查看該位置處未滿鏈?zhǔn)欠駷榭?,如果為空?zhí)行步驟25,否則執(zhí)行步驟23; 步驟23:從該未滿鏈中的第一個區(qū)段的空閑鏈中拿出空閑內(nèi)存塊分配給用戶使用,并把該內(nèi)存塊的頭部字段標(biāo)志位由空閑改為等差,并且修改區(qū)段中空閑鏈表,把該區(qū)段中的占用計數(shù)TEAM結(jié)構(gòu)體中的單元占用加I ; 步驟24:查看步驟23中分配區(qū)段的空閑鏈?zhǔn)欠駷榭?,如果為空,則把該區(qū)段以尾插法鏈入到相應(yīng)級別的滿鏈中,否者結(jié)束; 步驟25:如果未滿鏈為空,則需要擴充區(qū)段;首先申請加鎖,然后查看快鏈的管理數(shù)組中相應(yīng)級數(shù)的快鏈?zhǔn)欠駷榭?,如果不為空則執(zhí)行步驟26;如果為空,則執(zhí)行步驟27; 步驟26:從該快鏈中取出一個區(qū)段放入到第一層數(shù)組中,然后枚舉單元,并把該區(qū)段進(jìn)行掛接,然后解鎖,累加該區(qū)段所在鏈表頭部字段; 步驟27:計算實際分配長度,然后進(jìn)行申請并判斷是否成功,如果成功,則執(zhí)行步驟28,否者返回-1; 步驟28:按照對應(yīng)級數(shù)相應(yīng)的區(qū)段大小申請一塊內(nèi)存,并把該內(nèi)存劃分為小的內(nèi)存塊,標(biāo)注內(nèi)存塊頭部字段為空閑,整理空閑鏈,最后把該區(qū)段鏈入到第一層的未滿鏈中,然后分配給用戶需要使用的內(nèi)存; 步驟29:直接mal 1c從系統(tǒng)中申請,申請成功后,標(biāo)記內(nèi)存塊頭部字段為系統(tǒng),并返回給用戶使用,否則,返回-1。3.如權(quán)利要求1或2所述的一種面向非固定包長的無鎖化多鏈內(nèi)存管理方法,其特征在于:所述回收線程或進(jìn)程使用完的內(nèi)存,具體采用下列步驟: 步驟31:當(dāng)用戶釋放其使用的內(nèi)存時,首先根據(jù)需要釋放的內(nèi)存找到內(nèi)存塊的首地址; 步驟32:根據(jù)內(nèi)存塊頭部中類型標(biāo)記是否為0x02,如果不是從內(nèi)存池中申請得到的,則執(zhí)行步驟33,否者執(zhí)行步驟38; 步驟33:根據(jù)內(nèi)存塊頭部結(jié)構(gòu)體中的區(qū)號計算該區(qū)段的首地址,然后修改該區(qū)段的空閑鏈和占用計數(shù);判斷該區(qū)段的空閑鏈?zhǔn)欠駷榭?,若為空則執(zhí)行步驟34,否者執(zhí)行步驟35; 步驟34:如果該區(qū)段的空閑鏈為空,則把該區(qū)段從滿鏈中摘除并把該區(qū)段從尾部鏈入到非滿鏈中; 步驟35:如果該區(qū)段的空閑鏈非空,則歸還內(nèi)存塊,并修改內(nèi)存塊類型字段及區(qū)段和總結(jié)構(gòu)體中變量,然后是Held減I;最后判斷區(qū)段占用計數(shù)是否為0,若為0,則執(zhí)行步驟36,否則表示釋放內(nèi)存完成; 步驟36:如果占用計數(shù)為0,則說明該區(qū)段所有內(nèi)存塊全部未使用,這時需要把該區(qū)段從未滿鏈中摘除掉,然后執(zhí)行步驟37; 步驟37:從未滿鏈摘除以后,與衰減因子進(jìn)行比較,如果滿足衰減因子,則把該區(qū)段是返還給操作系統(tǒng),如果不滿足衰減因子,則直接把該區(qū)段放入到快鏈管理數(shù)組相對應(yīng)級別中的快鏈中; 步驟38:該內(nèi)存塊的內(nèi)存標(biāo)簽為系統(tǒng),直接把該內(nèi)存塊返還給操作系統(tǒng)。
【文檔編號】G06F12/02GK106095693SQ201610377594
【公開日】2016年11月9日
【申請日】2016年5月31日
【發(fā)明人】王嘯, 賀龍濤, 玄世昌, 張慧, 楊武, 曹首峰, 苘大鵬, 周立, 于賀威, 王大偉, 李城龍, 王秀文, 衛(wèi)冰潔, 李曉倩, 賀欣, 袁媛, 劉培朋, 朱佳偉, 劉陽
【申請人】國家計算機網(wǎng)絡(luò)與信息安全管理中心