山寨STL實現之記憶體池V2

2022-04-28 06:23:36 字數 2485 閱讀 8117

首先,改寫obj和block結構,在obj中加入乙個域released表示這個chunk是否被釋放

1struct obj

2     ;

1516

struct block

17     ;

其中的callstack部分將在下一節中介紹

然後,我們增加乙個結構

1 #ifdef _debug

2struct use

3     ;

7#endif

其中data域指向了一塊分配出去的小記憶體塊,next域形成了一張鍊錶。

然後,我們新增乙個成員變數來儲存這張鍊錶,以及乙個函式來將乙個chunk插入這張鍊錶

#ifdef _debug

use*      use_list;

#endif

#ifdef _debug

inline void memorypool::adduseinfo(obj* ptr)

#endif

然後,我們來改寫refill函式使其在分配記憶體塊時打上released標記,並將每個分配的記憶體塊記錄下來

1void* memorypool::refill(int i, void(*h)(size_type))

2 11     block* pblock = (block*)malloc(sizeof(block));

12while(pblock == 0)

13     

17     pblock->data = p;

18     pblock->next = free_list;

19     free_list = pblock;

2021     obj* current = (obj*)p;

22 #ifdef _debug

23     adduseinfo(current);

24     current->released = false;

25#endif

26     current = (obj*)((char*)current + presize);

27for(int j = 0; j < count - 1; ++j)

28     

37return (char*)p + headersize;

38 }

其中的headersize跟callstack有關,將在下一節中介紹。

當然,在deallocate時要將此記憶體塊的released標記打為true

1void memorypool::deallocate(void* p, size_type n)2 9

const

int i = index(round_up(n));

10 #ifdef _debug

11     p = (char*)p - (int)headersize;

12     obj* ptr = reinterpret_cast(p);

13if (ptr->released) throw error("chunk has already released", __file__, __line__);

14     ptr->released = true;

15#endif

16     reinterpret_cast(p)->next = chunk_list[i];

17     chunk_list[i] = reinterpret_cast(p);

18 }

ok,現在已經有模有樣了,可以鬆口氣了。接下來是最重要的部分,在memorypool析構時檢測這個pool內的use_list中是否有chunk的released標記為true(記憶體洩漏了)

1 memorypool::~memorypool()

2 13         free(ptr);

14         use_list = next;

15     }

16#endif

17     clear();

18 }

其實說來也容易,只需要檢測每個chunk的released標記是否為true就行了,而最後的clear函式是以前析構函式的**,用來釋放所有申請的block和大塊的chunk。

ok,現在我們已經可以檢測出沒有被deallocate的chunk了。

二、callstack

首先,我們先來看乙個windows api,「capturestackbacktrace」這個api通過傳入的乙個陣列來得到一組位址。當然有這個api並不夠,我們還需要知道是哪個檔案的第幾行。「symgetsymfromaddr64」這個api用來獲取某個位址對應的函式名,「symgetlinefromaddr64」這個api則是用來獲取某個位址對應的檔名和行號的,這兩個函式的32位版本則是不帶64的。有了這些windows api,我們就可以很輕鬆的獲取到當前函式的呼叫堆疊了,主要的功勞還是要歸功於windows強大的dbghelp。

最後,完整的**你可以在中找到。

山寨STL實現之記憶體池

記憶體池的作用 減少記憶體碎片,提高效能。首先不得不提的是win32和x64中對於指標的長度是不同的,在win32中乙個指標佔4位元組,而在x64中乙個指標佔8位元組。也正是不清楚這一點,當我在x64中將指標作為4位元組修改造成其他資料異常。首先我們先來定義三個巨集 define align siz...

STL原始碼分析之記憶體池

前言上一節只分析了第二級配置器是由多個鍊錶來存放相同記憶體大小,當沒有空間的時候就向記憶體池索取就行了,卻沒有具體分析記憶體池是怎麼儲存空間的,是不是記憶體池真的有用不完的記憶體,本節我們就具體來分析一下 記憶體池static data template的初始化 template char defa...

高效能之記憶體池

記憶體池 memory pool 是一種記憶體分配方式。通常我們習慣直接使用new malloc等api申請分配記憶體,這樣做的缺點在於 由於所申請記憶體塊的大小不定,當頻繁使用時會造成大量的記憶體碎片並進而降低效能。記憶體池則是在真正使用記憶體之前,先申請分配一定數量的 大小相等 一般情況下 的記...