第一級空間配置器
第一級配置器只是對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 ******_allocstatic 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函式僅僅是將資料清除,而申請的記憶體還是存在的,並沒有釋放掉。可以呼...