STL內(nèi)存分配方式解析&二級配置器源碼

內(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ù)介紹:

根據(jù)申請內(nèi)存獲取塊
根據(jù)申請內(nèi)存獲取塊所在的空閑數(shù)組下標(biāo)


申請內(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;


320分配好之后

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

byte使用,剩余塊用鏈表串起來。


申請7字節(jié)后內(nèi)存池示意圖。

此時再次申請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é)后情況為


獲取的內(nèi)存


申請17字節(jié)后內(nèi)存池示意圖

此時再次申請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)去,如圖所示:


剩余16分塊

之前申請的320用完了,重新申請,size_t alloc_bytes =2 * __total_bytes + _S_round_up(_S_heap_size >> 4);

申請的大小是1944個字節(jié)。申請后分配內(nèi)存結(jié)構(gòu)為


申請47字節(jié)后內(nèi)存示意圖

再次分配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)存配置

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容