內(nèi)存塊:
????每個內(nèi)存塊的大小均是8的倍數(shù),二級配置器默認(rèn)相同大小的塊用了20個,以鏈表的形式存放。
空閑數(shù)組:
????二級配置器維護(hù)了一個全局?jǐn)?shù)組 _S_free_list,長度為16,每個下標(biāo) 均保存包含 內(nèi)存塊的一個鏈表 鏈表;其中下標(biāo)為0的index保存塊大小為8的內(nèi)存塊鏈表指針,下標(biāo)為1的index保存塊為16的內(nèi)存塊鏈表指針;以此類推,下標(biāo)為15的index保存著內(nèi)存塊大小為128的內(nèi)存塊鏈表指針。每次申請內(nèi)存大于128 byte的采用第一級內(nèi)存配置器,直接malloc。
內(nèi)存申請流程:
????????內(nèi)存池不是開始就申請好的,而是首次使用時進(jìn)行申請,然后放進(jìn)空閑數(shù)組相應(yīng)塊的下標(biāo)中。
????仿照STL源碼,自己寫了內(nèi)存申請和釋放的流程,按照代碼走一遍;
函數(shù)介紹:




申請內(nèi)存時,按照申請的大小n進(jìn)行_S_freelist_index(n)查找空閑數(shù)組的下標(biāo),對_S_free_list 進(jìn)行偏移獲取對應(yīng)的塊鏈表頭。
按照源碼的申請流程:
以申請7個字節(jié)為例,根據(jù)_S_round_up 計算,應(yīng)該放在塊為8的鏈表中,默認(rèn)申請20個塊。
開始申請內(nèi)存,申請內(nèi)存大小的的換算是 size_t alloc_bytes =2 * __total_bytes + _S_round_up(_S_heap_size >> 4);
如果申請使用7字節(jié),那么會申請的內(nèi)存是 = 2*size(8)*__nobjs(20)+0 = 320;(_S_heap_size是總共從heap申請的大小,此時為0)
進(jìn)行malloc(320)操作,_S_start_free = (char*)malloc(alloc_bytes);
_S_heap_size += alloc_bytes;? _S_end_free = _S_start_free + alloc_bytes;
使用_S_start_free? 指向申請的空閑內(nèi)存起始處,_S_end_free 指向申請內(nèi)存的結(jié)束處。
申請好內(nèi)存后,對前160字節(jié)進(jìn)行先處理,后160暫時保留。 _S_start_free += __total_bytes;

接下來處理前160字節(jié)數(shù)據(jù),按照每塊8字節(jié)分為20塊,根據(jù)塊的大小為8 ,此塊應(yīng)存放在空閑數(shù)組中下標(biāo)為0的地方。第一個塊返回給用戶申請7
byte使用,剩余塊用鏈表串起來。

此時再次申請17個字節(jié),應(yīng)該在下標(biāo)為2,內(nèi)存塊大小為24的內(nèi)存鏈表中進(jìn)行操作,此時申請內(nèi)存計算值為24*20 = 480個字節(jié),之前剩余了160字節(jié),不夠480個字節(jié)使用,但夠一個塊(24)使用的,則對160進(jìn)行按照24為一塊進(jìn)行分配,可以分成160/24=6個塊,共用內(nèi)存144個字節(jié),此時獲取144字節(jié)后情況為


此時再次申請47個字節(jié)看內(nèi)存變化,47字節(jié)應(yīng)該放在下標(biāo)為5塊大小為48的鏈表中,鏈表為空,需要申請內(nèi)存,此時內(nèi)存池剩余空間為16字節(jié),既不滿足需要的大小 48*20=960字節(jié),也不滿足大于一個塊的大小。需要將16字節(jié)分配到相應(yīng)塊中去之后才再次重新申請大的內(nèi)存,16大小的塊應(yīng)該放在下標(biāo)為1的內(nèi)存鏈表中,使用頭插法放進(jìn)去,如圖所示:

之前申請的320用完了,重新申請,size_t alloc_bytes =2 * __total_bytes + _S_round_up(_S_heap_size >> 4);
申請的大小是1944個字節(jié)。申請后分配內(nèi)存結(jié)構(gòu)為

再次分配47時,直接從下表為5的塊48鏈表中取出頭結(jié)點(編號為2的塊)使用,然后空閑節(jié)點指向下一個節(jié)點。
釋放節(jié)點時,以第一個申請的7字節(jié)為例,將此塊頭插法插入空閑鏈表即可。
關(guān)于STL源碼 自己復(fù)制了一份簡單修改了下,去掉了關(guān)于第一級大于128字節(jié)申請的邏輯,可以直接運(yùn)行調(diào)試:
源碼地址:STL二級內(nèi)存配置