STL 記憶體的配置與釋放

2021-09-20 18:15:44 字數 3177 閱讀 7245

第一級空間配置器

第一級配置器只是對malloc函式和free函式的簡單封裝,在allocate內呼叫malloc,在deallocate內呼叫free。同時第一級配置器的oom_malloc函式,用來處理malloc失敗的情況。如下所示:

allocate對malloc函式簡單封裝 :

static void *allocate(size_t n)

deallocate對free函式簡單封裝 :

static void deallocate(void *p, size_t)

oom_malloc呼叫外部提供的malloc失敗處理函式,然後重新試著再次呼叫malloc。重複執行此過程,直到malloc成功為止 : 

template void* __malloc_alloc::oom_malloc(size_t n)

}

第二級空間配置器

第一級配置器直接呼叫malloc和free帶來了幾個問題:

1.記憶體分配/釋放的效率低。2. 當配置大量的小記憶體塊時,會導致記憶體碎片比較嚴重。3. 配置記憶體時,需要額外的部分空間儲存記憶體塊資訊,所以配置大量的小記憶體塊時,還會導致額外記憶體負擔。

第二級配置器維護了乙個自由鍊錶陣列,每次需要分配記憶體時,直接從相應的鍊錶上取出乙個記憶體節點就完成工作,效率很高。

自由鍊錶陣列

自由鍊錶陣列其實就是個指標陣列,陣列中的每個指標元素指向乙個鍊錶的起始節點。陣列大小為16,即維護了16個鍊錶,鍊錶的每個節點就是實際的記憶體塊,相同鍊錶上的記憶體塊大小都相同,不同鍊錶的記憶體塊大小不同,從8一直到128。如下所示,obj為鍊錶上的節點,free_list就是鍊錶陣列。

//自由鍊錶union obj

;//自由鍊錶陣列static obj *volatile free_list[__nfreelists];

記憶體分配

allocate函式內先判斷要分配的記憶體大小,若大於128位元組,直接呼叫第一級配置器,否則根據要分配的記憶體大小從16個鍊錶中選出乙個鍊錶,取出該鍊錶的第乙個節點。若相應的鍊錶為空,則呼叫refill函式填充該鍊錶。如下:

template void *__default_alloc::allocate(size_t n)

*my_free_list = result->free_list_link;        return result;

}

填充鍊錶

若allocate函式內要取出節點的鍊錶為空,則會呼叫refill函式填充該鍊錶。

refill函式內會先呼叫chunk_alloc函式從記憶體池分配一大塊記憶體,該記憶體大小預設為20個鍊錶節點大小,當記憶體池的記憶體也不足時,返回的記憶體塊節點數目會不足20個。接著refill的工作就是將這一大塊記憶體分成20份相同大小的記憶體塊,並將各記憶體塊連線起來形成乙個鍊錶。如下:

template void *__default_alloc::refill(size_t n)

//最後一塊

current_obj = next_obj;

current_obj->free_list_link = null;        return result;

}

記憶體池

chunk_alloc函式內管理了一塊記憶體池,當refill函式要填充鍊錶時,就會呼叫chunk_alloc函式,從記憶體池取出相應的記憶體。

在chunk_alloc函式內首先判斷記憶體池大小是否足夠填充乙個有20個節點的鍊錶,若記憶體池足夠大,則直接返回20個記憶體節點大小的記憶體塊給refill。如下:

if (size_left >= total_size)  //記憶體池剩餘空間滿足需求

若記憶體池大小無法滿足20個記憶體節點的大小,但至少滿足1個記憶體節點,則直接返回相應的記憶體節點大小的記憶體塊給refill;

else if (size_left >= size)  //剩餘空間不能全部滿足,但至少滿足一塊                else if (size_left >= size)  //剩餘空間不能全部滿足,但至少滿足一塊                else  //連乙個區塊都無法滿足        

size_t bytes_to_get = 2 * total_size + round_up(heap_size >> 4);

start_free = (char *)malloc(bytes_to_get);                if (start_free == null)  //堆空間不足                

}end_free = null;                        //呼叫第一級配置器

start_free = (char *)malloc_alloc::allocate(bytes_to_get);

}heap_size += bytes_to_get;

end_free = start_free + heap_size;                return chunk_alloc(size, nobjs);

}}

記憶體釋放

第二級配置器的deallocate函式並不會直接釋放記憶體塊。當記憶體塊大小大於128位元組時才會直接釋放,否則會將記憶體塊**到相應的鍊錶當中。如下:

void __default_alloc::deallocate(void *p, size_t n)

記憶體對外介面

stl對外提供了乙個******_alloc類,該類提供統一的介面:allocate函式、deallocate函式,使得外部無需關心使用的是幾級記憶體配置器。另外******_alloc類將外部所需的物件個數轉換為位元組。如下。

template class ******_alloc

static t *allocate(void)

static void deallocate(t *p, size_t n) // 個數                static void deallocate(t *p)

};

sshpp

STL原始碼剖析 記憶體配置和釋放

其中 malloc alloc template public static void allocate size t n 直到分配成功返回或拋異常,呼叫 oom malloc static void deallocate void p,size t n static void reallocate...

STL中Vector的記憶體釋放問題

vector是stl中最常見的模板之一,其記憶體是連續的。vector的大小有size和capacity之別,記憶體可以動態增長。vector呼叫clear 之後,只會把size設定為0,而記憶體空間並沒有釋放。vector 中的內建有記憶體管理,當 vector 離開它的生存期的時候,它的析構函式...

STL 如何釋放vector占用的記憶體

c stl中vector的相關問題,呼叫clear時,內部是如何具體實現的?若想將其記憶體釋放,該如何操作?假設我們先定義乙個容器x vectorx 100 這樣首先會申請 100 sizeof int 的記憶體大小。呼叫clear函式僅僅是將資料清除,而申請的記憶體還是存在的,並沒有釋放掉。可以呼...