C STL 的記憶體優化

2021-09-24 20:03:39 字數 2296 閱讀 4162

1)二級配置器結構

stl記憶體管理使用二級記憶體配置器

1、第一級配置器

第一級配置器以malloc(),free(),realloc()等c函式執行實際的記憶體配置、釋放、重新配置等操作,並且能在記憶體需求不被滿足的時候,呼叫乙個指定的函式。

一級空間配置器分配的是大於128位元組的空間

如果分配不成功,呼叫控制代碼釋放一部分記憶體

如果還不能分配成功,丟擲異常

2、第二級配置器

在stl的第二級配置器中多了一些機制,避免太多小區塊造成的記憶體碎片,小額區塊帶來的不僅是記憶體碎片,配置時還有額外的負擔。區塊越小,額外負擔所佔比例就越大。

3、分配原則

如果要分配的區塊大於128bytes,則移交給第一級配置器處理。

如果要分配的區塊小於128bytes,則以記憶體池管理(memory pool),又稱之次層配置(sub-allocation):每次配置一大塊記憶體,並維護對應的16個空閒鍊錶(free-list)。下次若有相同大小的記憶體需求,則直接從free-list中取。如果有小額區塊被釋放,則由配置器**到free-list中。

當使用者申請的空間小於128位元組時,將位元組數擴充套件到8的倍數,然後在自由鍊錶中查詢對應大小的子鍊錶

如果在自由鍊錶查詢不到或者塊數不夠,則向記憶體池進行申請,一般一次申請20塊

如果記憶體池空間足夠,則取出記憶體

如果不夠分配20塊,則分配最多的塊數給自由鍊錶,並且更新每次申請的塊數

如果一塊都無法提供,則把剩餘的記憶體掛到自由鍊錶,然後向系統heap申請空間,如果申請失敗,則看看自由鍊錶還有沒有可用的塊,如果也沒有,則最後呼叫一級空間配置器

2)二級記憶體池

二級記憶體池採用了16個空閒鍊錶,這裡的16個空閒鍊錶分別管理大小為8、16、24…120、128的資料塊。這裡空閒鍊錶節點的設計十分巧妙,這裡用了乙個聯合體既可以表示下乙個空閒資料塊(存在於空閒鍊錶中)的位址,也可以表示已經被使用者使用的資料塊(不存在空閒鍊錶中)的位址。

1、空間配置函式allocate

首先先要檢查申請空間的大小,如果大於128位元組就呼叫第一級配置器,小於128位元組就檢查對應的空閒鍊錶,如果該空閒鍊錶中有可用資料塊,則直接拿來用(拿取空閒鍊錶中的第乙個可用資料塊,然後把該空閒鍊錶的位址設定為該資料塊指向的下乙個位址),如果沒有可用資料塊,則呼叫refill重新填充空間

2、空間釋放函式deallocate

首先先要檢查釋放資料塊的大小,如果大於128位元組就呼叫第一級配置器,小於128位元組則根據資料塊的大小來判斷**後的空間會被插入到哪個空閒鍊錶

3、重新填充空閒鍊錶refill

在用allocate配置空間時,如果空閒鍊錶中沒有可用資料塊,就會呼叫refill來重新填充空間,新的空間取自記憶體池。預設取20個資料塊,如果記憶體池空間不足,那麼能取多少個節點就取多少個。

從記憶體池取空間給空閒鍊錶用是chunk_alloc的工作,首先根據end_free-start_free來判斷記憶體池中的剩餘空間是否足以調出nobjs個大小為size的資料塊出去,如果記憶體連乙個資料塊的空間都無法**,需要用malloc取堆中申請記憶體。

假如山窮水盡,整個系統的堆空間都不夠用了,malloc失敗,那麼chunk_alloc會從空閒鍊錶中找是否有大的資料塊,然後將該資料塊的空間分給記憶體池(這個資料塊會從鍊錶中去除)。

3、總結:

使用allocate向記憶體池請求size大小的記憶體空間,如果需要請求的記憶體大小大於128bytes,直接使用malloc。

如果需要的記憶體大小小於128bytes,allocate根據size找到最適合的自由鍊錶。

a. 如果鍊錶不為空,返回第乙個node,煉表頭改為第二個node。

b. 如果鍊錶為空,使用blockalloc請求分配node。

x. 如果記憶體池中有大於乙個node的空間,分配竟可能多的node(但是最多20個),將乙個node返回,其他的node新增到鍊錶中。

y. 如果記憶體池只有乙個node的空間,直接返回給使用者。

z. 若果如果連乙個node都沒有,再次向作業系統請求分配記憶體。

①分配成功,再次進行b過程。

②分配失敗,迴圈各個自由鍊錶,尋找空間。

i. 找到空間,再次進行過程b。

ii. 找不到空間,丟擲異常。

使用者呼叫deallocate釋放記憶體空間,如果要求釋放的記憶體空間大於128bytes,直接呼叫free。

c stl記憶體分配

sgi stl中stl 的記憶體分配不是採用allocator類,而是採用自己寫的類alloc 這個alloc類中主要有四個函式 construct 用於呼叫新建類的建構函式,其實現就是依靠placement new destroy 用於呼叫新建類的析構函式 allocate 用於分配新建類的記憶體...

C STL記憶體池

記憶體池出現原因 記憶體碎片 首先我們需要明確,記憶體池的目的到底是什麼?首先你要知道的是,我們每次使用new t來初始化型別t的時候,其實發生了兩步操作,乙個叫記憶體分配,這一步使用的其實不是new而是operator new 也可以認為就是c語言中的malloc 這一步是直接和作業系統打交道的,...

C STL中各容器記憶體 優劣的分析

各種容器的元素在記憶體中的儲存方式 1 vector 向量 相當於陣列,但其大小可以不預先指定,並且自動擴充套件。它可以像陣列一樣被操作,由於它的特性我們完全可以將vector 看作動態陣列。在建立乙個vector 後,它會自動在記憶體中分配一塊連續的 記憶體空間進行資料儲存,初始的空間大小可以預先...