1. 程式人生 > >C++實現記憶體池

C++實現記憶體池

浪費了“黃金五年”的Java程式設計師,還有救嗎? >>>   

1. 記憶體池設計

1.1 目的

在給定的記憶體buffer上建立記憶體管理機制,根據使用者需求從該buffer上分配記憶體或者將已經分配的記憶體釋放回buffer中。

1.2 要求

儘量減少記憶體碎片,平均效率高於C語言的malloc和free。

1.3 設計思路

將buffer分為四部分,第1部分是mem_pool結構體;第2部分是記憶體對映表;第3部分是記憶體chunk結構體緩衝區;第4部分是實際可分配的記憶體區。整個buffer結構圖如圖1所示:

圖1 記憶體buffer結構圖

圖1 記憶體buffer結構圖

第1部分的作用是可以通過該mem_pool結構體控制整個記憶體池。

第2部分的作用是記錄第4部分,即實際可分配的記憶體區的使用情況。表中的每一個單元表示一個固定大小的記憶體塊(block),多個連續的block組成一個chunk,每個block的詳細結構如圖2所示:

圖2 memory block結構圖

圖2 memory block結構圖

其中count表示該block後面的與該block同屬於一個chunk的blokc的個數,start表示該block所在的chunk的起始block索引。其實start這個域只有在每個chunk的最後一個block中才會用到(用於從當前chunk尋找前一個chunk的起始位置),而pmem_chunk則是一個指標,指向一個mem_chunk結構體。任意一塊大小的記憶體都會被取向上整到block大小的整數倍。

第3部分是一個mem_chunk pool,其作用是儲存整個程式可用的mem_chunk結構體。mem_chunk pool中的mem_chunk被組織成雙向連結串列結構(快速插入和刪除)。每個mem_chunk結構圖如圖3所示:

圖3 memory chunk結構圖

圖3 memory chunk結構圖

其中pmem_block指向該chunk在記憶體對映表中的位置,others表示其他一些域,不同的實現對應該域的內容略有不同。

第4部分就是實際可以被分配給使用者的記憶體。

整個記憶體池管理程式除了這四部分外,還有一個重要的內容就是memory chunk set。雖然其中的每個元素都來自mem_chunk pool,但是它與mem_chunk pool的不同之處在於其中的每個memory chunk中記錄了當前可用的一塊記憶體的相關資訊。而mem_chunk pool中的memory chunk的內容是無定以的。可以這樣理解mem_chunk pool與memory chunk set:mem_chunk pool是為memory chunk set分配記憶體的“記憶體池”,只是該“記憶體池”每次分配的記憶體大小是固定的,為mem_chunk結構體的大小。記憶體池程式主要是通過搜尋這個memory chunk set來獲取可被分配的記憶體。在memory chunk set上建立不同的資料結構就構成了不同的記憶體池實現方法,同時也導致了不同的搜尋效率,直接影響記憶體池的效能,本文稍後會介紹兩種記憶體池的實現。

1.4 記憶體池管理程式執行過程

  • 初始化:記憶體對映表中只有一塊可用的記憶體資訊,大小為記憶體池中所有可用的記憶體。從memory chunk pool中分配一個mem_chunk,使其指向記憶體對映表中的第一個block,並根據具體的記憶體池實現方式填充mem_chunk中的其他域,然後將該mem_chunk新增到memory chunk set中。
  • 申請記憶體:當用戶申請一塊記憶體時,首先在memory chunk set中查詢合適的記憶體塊。如果找到符合要求的記憶體塊,就在記憶體對映表中找到相應的chunk,並修改chunk中相應block結構體的內容,然後根據修改後的chunk修改memory chunk set中chunk的內容,最後返回分配記憶體的起始地址;否則返回NULL。
  • 釋放記憶體:當用戶釋放一塊記憶體時,首先根據這塊記憶體的起始地址找到其在記憶體對映表中對應的chunk,然後嘗試將該chunk和與其相鄰的chunk合併,修改chunk中相應block的內容並修改memory chunk set中相應chunk的內容或者向memory chunk set加入新的mem_chunk(這種情況在不能合併記憶體是發生)。

1.5 減少記憶體碎片

本文設計的方法只能在一定程度上減少記憶體碎片,並不能徹底消除記憶體碎片。具體方法如下:

在使用者釋放記憶體時,嘗試將該記憶體與其相鄰的記憶體合併。如果其相鄰記憶體為未分配記憶體則合併成功,合併後作為一整塊記憶體使用;如火其相鄰記憶體為已分配記憶體則不能合併,該釋放的記憶體塊作為一個獨立的記憶體塊被使用。

2 記憶體池實現-連結串列結構

2.1 效能分析

連結串列結構的記憶體池實現是指將memory chunk set實現為雙鏈表結構。這種方法的優缺點如下:

優點:釋放記憶體很快,O(1)複雜度。

缺點:分配記憶體較慢,O(n)複雜度。

2.2 記憶體池執行狀態轉移圖

綠色表示未使用的記憶體,紅色表示已經使用的記憶體。其中每個block表示64B,這個值可以根據具體需要設定。

  • 初始化

圖4 記憶體池初始化狀態

圖4 記憶體池初始化狀態

  • 申請記憶體

圖5 第1次申請128B記憶體後

圖5 第1次申請128B記憶體後

圖6 第n次申請、釋放記憶體後

圖6 第n次申請、釋放記憶體後

  • 釋放記憶體

 

圖7 釋放64B記憶體前後

圖7 釋放64B記憶體前後

3 記憶體池實現-大頂堆結構

3.1 效能分析

 

大頂堆結構的記憶體池實現是指將memory chunk set實現為大頂堆結構。這種方法的優缺點如下:

優點:降低了分配記憶體的時間複雜度,O(log(n))。

缺點:增加了釋放記憶體的時間複雜度,O(log(n))。

3.2 記憶體池執行狀態轉移圖

綠色表示未使用的記憶體,紅色表示已經使用的記憶體。其中每個block表示64B,這個值可以根據具體需要設定。

  • 初始化

圖8 記憶體池初始化狀態

圖8 記憶體池初始化狀態

  • 申請記憶體

圖9 第1次申請128B記憶體後

圖9 第1次申請128B記憶體後

圖10 第n次申請、釋放記憶體後

圖10 第n次申請、釋放記憶體後

  • 釋放記憶體

圖11 釋放64B記憶體前後

圖11 釋放64B記憶體前後

4 效能測試

  • 測試物件:C語言的malloc、free和本文的兩種記憶體池(大小為500M,實際可分配記憶體為310M)。
  • 測試指標:執行n=2000次隨機分配、釋放隨機大小記憶體(範圍為64B~1024B)的時間比。
  • 測試方法1:

(1) 生成n個隨機數,大小在64~1024之間,用於表示n個要分配的記憶體大小;

(2) 生成n個隨機數,取值 為0或者1,表示每次分配記憶體後緊接著是否釋放記憶體;

(3) 測量C語言的malloc、free和本文兩種記憶體池執行n次隨機分配、釋放隨機大小記憶體的時間比ratio;

(4) 重複(3)m=200次,記錄每次活動的ratio,並繪製相應的曲線。

  • 測試方法2:

(1) 生成n個隨機數,大小在a~b之間(初始值a=64,b=1024),用於表示n個要分配的記憶體大小;

(2) 測量C語言的malloc、free和本文兩種記憶體池執行n次分配、釋放隨機大小記憶體的時間比ratio;

(3) 重複(2)m=512次,每次分配的記憶體容量的範圍比前一次大1024B,記錄每次獲得的ratio,並繪製相應曲線。

4.1 效能測試結果-連結串列結果記憶體池

圖12 連結串列結構記憶體池效能測試結果1

圖12 連結串列結構記憶體池效能測試結果1

連結串列結構記憶體池效能測試結果2

圖13 連結串列結構記憶體池效能測試結果2

4.2 效能測試結果-大頂堆結構記憶體池

圖14 大頂堆記憶體池效能測試結果1

圖14 大頂堆記憶體池效能測試結果1

圖15 大頂堆記憶體池效能測試結果2

圖15 大頂堆記憶體池效能測試結果2

4.3 效能比較

圖16 兩種記憶體池效能測試結果比較1

圖16 兩種記憶體池效能測試結果比較1

圖17 兩種記憶體池效能測試結果比較2

圖17 兩種記憶體池效能測試結果比較2

5 結論

從上面的記憶體池效能測試結果中可以看出,相比C語言的malloc和free,記憶體池使得使用者分配記憶體和釋放記憶體的效率有了較大的提高,這一優勢尤其分配較大快的記憶體時體現的尤為突出。

同時也可以看出大頂堆結夠的記憶體池的效能並不比連結串列結構的記憶體池效能高,反而低於連結串列結構記憶體池的效能。這再一次表明O(log(n))優於O(n)是有條件的。當然,本文的測試具有一定的侷限性,也許在其他的測試案例中大頂堆結構的記憶體池效能會超越連結串列結構的記憶體池。

附:原始碼

連結串列結構記憶體池:

MemoryPool.h

 
  1. #ifndef _MEMORYPOOL_H

  2. #define _MEMORYPOOL_H

  3. #include <stdlib.h>

  4. #define MINUNITSIZE 64

  5. #define ADDR_ALIGN 8

  6. #define SIZE_ALIGN MINUNITSIZE

  7. struct memory_chunk;

  8. typedef struct memory_block

  9. {

  10. size_t count;

  11. size_t start;

  12. memory_chunk* pmem_chunk;

  13. }memory_block;

  14. // 可用的記憶體塊結構體

  15. typedef struct memory_chunk

  16. {

  17. memory_block* pfree_mem_addr;

  18. memory_chunk* pre;

  19. memory_chunk* next;

  20. }memory_chunk;

  21. // 記憶體池結構體

  22. typedef struct MEMORYPOOL

  23. {

  24. void *memory;

  25. size_t size;

  26. memory_block* pmem_map;

  27. memory_chunk* pfree_mem_chunk;

  28. memory_chunk* pfree_mem_chunk_pool;

  29. size_t mem_used_size; // 記錄記憶體池中已經分配給使用者的記憶體的大小

  30. size_t mem_map_pool_count; // 記錄連結串列單元緩衝池中剩餘的單元的個數,個數為0時不能分配單元給pfree_mem_chunk

  31. size_t free_mem_chunk_count; // 記錄 pfree_mem_chunk連結串列中的單元個數

  32. size_t mem_map_unit_count; //

  33. size_t mem_block_count; // 一個 mem_unit 大小為 MINUNITSIZE

  34. }MEMORYPOOL, *PMEMORYPOOL;

  35. /************************************************************************/

  36. /* 生成記憶體池

  37. * pBuf: 給定的記憶體buffer起始地址

  38. * sBufSize: 給定的記憶體buffer大小

  39. * 返回生成的記憶體池指標

  40. /************************************************************************/

  41. PMEMORYPOOL CreateMemoryPool(void* pBuf, size_t sBufSize);

  42. /************************************************************************/

  43. /* 暫時沒用

  44. /************************************************************************/

  45. void ReleaseMemoryPool(PMEMORYPOOL* ppMem) ;

  46. /************************************************************************/

  47. /* 從記憶體池中分配指定大小的記憶體

  48. * pMem: 記憶體池 指標

  49. * sMemorySize: 要分配的記憶體大小

  50. * 成功時返回分配的記憶體起始地址,失敗返回NULL

  51. /************************************************************************/

  52. void* GetMemory(size_t sMemorySize, PMEMORYPOOL pMem) ;

  53.  
  54. /************************************************************************/

  55. /* 從記憶體池中釋放申請到的記憶體

  56. * pMem:記憶體池指標

  57. * ptrMemoryBlock:申請到的記憶體起始地址

  58. /************************************************************************/

  59. void FreeMemory(void *ptrMemoryBlock, PMEMORYPOOL pMem) ;

  60.  
  61. #endif //_MEMORYPOOL_H

MemoryPool.cpp

 
  1. #include "stdafx.h"

  2. #include <memory.h>

  3. #include "MemoryPool.h"

  4. /************************************************************************/

  5. /* 記憶體池起始地址對齊到ADDR_ALIGN位元組

  6. /************************************************************************/

  7. size_t check_align_addr(void*& pBuf)

  8. {

  9. size_t align = 0;

  10. size_t addr = (int)pBuf;

  11. align = (ADDR_ALIGN - addr % ADDR_ALIGN) % ADDR_ALIGN;

  12. pBuf = (char*)pBuf + align;

  13. return align;

  14. }

  15. /************************************************************************/

  16. /* 記憶體block大小對齊到MINUNITSIZE位元組

  17. /************************************************************************/

  18. size_t check_align_block(size_t size)

  19. {

  20. size_t align = size % MINUNITSIZE;

  21.  
  22. return size - align;

  23. }

  24. /************************************************************************/

  25. /* 分配記憶體大小對齊到SIZE_ALIGN位元組

  26. /************************************************************************/

  27. size_t check_align_size(size_t size)

  28. {

  29. size = (size + SIZE_ALIGN - 1) / SIZE_ALIGN * SIZE_ALIGN;

  30. return size;

  31. }

  32. /************************************************************************/

  33. /* 以下是連結串列相關操作

  34. /************************************************************************/

  35. memory_chunk* create_list(memory_chunk* pool, size_t count)

  36. {

  37. if (!pool)

  38. {

  39. return NULL;

  40. }

  41. memory_chunk* head = NULL;

  42. for (size_t i = 0; i < count; i++)

  43. {

  44. pool->pre = NULL;

  45. pool->next = head;

  46. if (head != NULL)

  47. {

  48. head->pre = pool;

  49. }

  50. head = pool;

  51. pool++;

  52. }

  53. return head;

  54. }

  55. memory_chunk* front_pop(memory_chunk*& pool)

  56. {

  57. if (!pool)

  58. {

  59. return NULL;

  60. }

  61. memory_chunk* tmp = pool;

  62. pool = tmp->next;

  63. pool->pre = NULL;

  64. return tmp;

  65. }

  66. void push_back(memory_chunk*& head, memory_chunk* element)

  67. {

  68. if (head == NULL)

  69. {

  70. head = element;

  71. head->pre = element;

  72. head->next = element;

  73. return;

  74. }

  75. head->pre->next = element;

  76. element->pre = head->pre;

  77. head->pre = element;

  78. element->next = head;

  79. }

  80. void push_front(memory_chunk*& head, memory_chunk* element)

  81. {

  82. element->pre = NULL;

  83. element->next = head;

  84. if (head != NULL)

  85. {

  86. head->pre = element;

  87. }

  88. head = element;

  89. }

  90. void delete_chunk(memory_chunk*& head, memory_chunk* element)

  91. {

  92. // 在雙迴圈連結串列中刪除元素

  93. if (element == NULL)

  94. {

  95. return;

  96. }

  97. // element為連結串列頭

  98. else if (element == head)

  99. {

  100. // 連結串列只有一個元素

  101. if (head->pre == head)

  102. {

  103. head = NULL;

  104. }

  105. else

  106. {

  107. head = element->next;

  108. head->pre = element->pre;

  109. head->pre->next = head;

  110. }

  111. }

  112. // element為連結串列尾

  113. else if (element->next == head)

  114. {

  115. head->pre = element->pre;

  116. element->pre->next = head;

  117. }

  118. else

  119. {

  120. element->pre->next = element->next;

  121. element->next->pre = element->pre;

  122. }

  123. element->pre = NULL;

  124. element->next = NULL;

  125. }

  126. /************************************************************************/

  127. /* 記憶體對映表中的索引轉化為記憶體起始地址

  128. /************************************************************************/

  129. void* index2addr(PMEMORYPOOL mem_pool, size_t index)

  130. {

  131. char* p = (char*)(mem_pool->memory);

  132. void* ret = (void*)(p + index *MINUNITSIZE);

  133.  
  134. return ret;

  135. }

  136. /************************************************************************/

  137. /* 記憶體起始地址轉化為記憶體對映表中的索引

  138. /************************************************************************/

  139. size_t addr2index(PMEMORYPOOL mem_pool, void* addr)

  140. {

  141. char* start = (char*)(mem_pool->memory);

  142. char* p = (char*)addr;

  143. size_t index = (p - start) / MINUNITSIZE;

  144. return index;

  145. }

  146. /************************************************************************/

  147. /* 生成記憶體池

  148. * pBuf: 給定的記憶體buffer起始地址

  149. * sBufSize: 給定的記憶體buffer大小

  150. * 返回生成的記憶體池指標

  151. /************************************************************************/

  152. PMEMORYPOOL CreateMemoryPool(void* pBuf, size_t sBufSize)

  153. {

  154. memset(pBuf, 0, sBufSize);

  155. PMEMORYPOOL mem_pool = (PMEMORYPOOL)pBuf;

  156. // 計算需要多少memory map單元格

  157. size_t mem_pool_struct_size = sizeof(MEMORYPOOL);

  158. mem_pool->mem_map_pool_count = (sBufSize - mem_pool_struct_size + MINUNITSIZE - 1) / MINUNITSIZE;

  159. mem_pool->mem_map_unit_count = (sBufSize - mem_pool_struct_size + MINUNITSIZE - 1) / MINUNITSIZE;

  160. mem_pool->pmem_map = (memory_block*)((char*)pBuf + mem_pool_struct_size);

  161. mem_pool->pfree_mem_chunk_pool = (memory_chunk*)((char*)pBuf + mem_pool_struct_size + sizeof(memory_block) * mem_pool->mem_map_unit_count);

  162.  
  163. mem_pool->memory = (char*)pBuf + mem_pool_struct_size+ sizeof(memory_block) * mem_pool->mem_map_unit_count + sizeof(memory_chunk) * mem_pool->mem_map_pool_count;

  164. mem_pool->size = sBufSize - mem_pool_struct_size - sizeof(memory_block) * mem_pool->mem_map_unit_count - sizeof(memory_chunk) * mem_pool->mem_map_pool_count;

  165. size_t align = check_align_addr(mem_pool->memory);

  166. mem_pool->size -= align;

  167. mem_pool->size = check_align_block(mem_pool->size);

  168. mem_pool->mem_block_count = mem_pool->size / MINUNITSIZE;

  169. // 連結串列化

  170. mem_pool->pfree_mem_chunk_pool = create_list(mem_pool->pfree_mem_chunk_pool, mem_pool->mem_map_pool_count);

  171. // 初始化 pfree_mem_chunk,雙向迴圈連結串列

  172. memory_chunk* tmp = front_pop(mem_pool->pfree_mem_chunk_pool);

  173. tmp->pre = tmp;

  174. tmp->next = tmp;

  175. tmp->pfree_mem_addr = NULL;

  176. mem_pool->mem_map_pool_count--;

  177.  
  178. // 初始化 pmem_map

  179. mem_pool->pmem_map[0].count = mem_pool->mem_block_count;

  180. mem_pool->pmem_map[0].pmem_chunk = tmp;

  181. mem_pool->pmem_map[mem_pool->mem_block_count-1].start = 0;

  182.  
  183. tmp->pfree_mem_addr = mem_pool->pmem_map;

  184. push_back(mem_pool->pfree_mem_chunk, tmp);

  185. mem_pool->free_mem_chunk_count = 1;

  186. mem_pool->mem_used_size = 0;

  187. return mem_pool;

  188. }

  189. /************************************************************************/

  190. /* 暫時沒用

  191. /************************************************************************/

  192. void ReleaseMemoryPool(PMEMORYPOOL* ppMem)

  193. {

  194. }

  195. /************************************************************************/

  196. /* 從記憶體池中分配指定大小的記憶體

  197. * pMem: 記憶體池 指標

  198. * sMemorySize: 要分配的記憶體大小

  199. * 成功時返回分配的記憶體起始地址,失敗返回NULL

  200. /************************************************************************/

  201. void* GetMemory(size_t sMemorySize, PMEMORYPOOL pMem)

  202. {

  203. sMemorySize = check_align_size(sMemorySize);

  204. size_t index = 0;

  205. memory_chunk* tmp = pMem->pfree_mem_chunk;

  206. for (index = 0; index < pMem->free_mem_chunk_count; index++)

  207. {

  208. if (tmp->pfree_mem_addr->count * MINUNITSIZE >= sMemorySize)

  209. {

  210. break;

  211. }

  212.  
  213. tmp = tmp->next;

  214. }

  215.  
  216. if (index == pMem->free_mem_chunk_count)

  217. {

  218. return NULL;

  219. }

  220. pMem->mem_used_size += sMemorySize;

  221. if (tmp->pfree_mem_addr->count * MINUNITSIZE == sMemorySize)

  222. {

  223. // 當要分配的記憶體大小與當前chunk中的記憶體大小相同時,從pfree_mem_chunk連結串列中刪除此chunk

  224. size_t current_index = (tmp->pfree_mem_addr - pMem->pmem_map);

  225. delete_chunk(pMem->pfree_mem_chunk, tmp);

  226. tmp->pfree_mem_addr->pmem_chunk = NULL;

  227.  
  228. push_front(pMem->pfree_mem_chunk_pool, tmp);

  229. pMem->free_mem_chunk_count--;

  230. pMem->mem_map_pool_count++;

  231.  
  232. return index2addr(pMem, current_index);

  233. }

  234. else

  235. {

  236. // 當要分配的記憶體小於當前chunk中的記憶體時,更改pfree_mem_chunk中相應chunk的pfree_mem_addr

  237.  
  238. // 複製當前mem_map_unit

  239. memory_block copy;

  240. copy.count = tmp->pfree_mem_addr->count;

  241. copy.pmem_chunk = tmp;

  242. // 記錄該block的起始和結束索引

  243. memory_block* current_block = tmp->pfree_mem_addr;

  244. current_block->count = sMemorySize / MINUNITSIZE;

  245. size_t current_index = (current_block - pMem->pmem_map);

  246. pMem->pmem_map[current_index+current_block->count-1].start = current_index;

  247. current_block->pmem_chunk = NULL; // NULL表示當前記憶體塊已被分配

  248. // 當前block被一分為二,更新第二個block中的內容

  249. pMem->pmem_map[current_index+current_block->count].count = copy.count - current_block->count;

  250. pMem->pmem_map[current_index+current_block->count].pmem_chunk = copy.pmem_chunk;

  251. // 更新原來的pfree_mem_addr

  252. tmp->pfree_mem_addr = &(pMem->pmem_map[current_index+current_block->count]);

  253.  
  254. size_t end_index = current_index + copy.count - 1;

  255. pMem->pmem_map[end_index].start = current_index + current_block->count;

  256. return index2addr(pMem, current_index);

  257. }

  258. }

  259. /************************************************************************/

  260. /* 從記憶體池中釋放申請到的記憶體

  261. * pMem:記憶體池指標

  262. * ptrMemoryBlock:申請到的記憶體起始地址

  263. /************************************************************************/

  264. void FreeMemory(void *ptrMemoryBlock, PMEMORYPOOL pMem)

  265. {

  266. size_t current_index = addr2index(pMem, ptrMemoryBlock);

  267. size_t size = pMem->pmem_map[current_index].count * MINUNITSIZE;

  268. // 判斷與當前釋放的記憶體塊相鄰的記憶體塊是否可以與當前釋放的記憶體塊合併

  269. memory_block* pre_block = NULL;

  270. memory_block* next_block = NULL;

  271. memory_block* current_block = &(pMem->pmem_map[current_index]);

  272. // 第一個

  273. if (current_index == 0)

  274. {

  275. if (current_block->count < pMem->mem_block_count)

  276. {

  277. next_block = &(pMem->pmem_map[current_index+current_block->count]);

  278. // 如果後一個記憶體塊是空閒的,合併

  279. if (next_block->pmem_chunk != NULL)

  280. {

  281. next_block->pmem_chunk->pfree_mem_addr = current_block;

  282. pMem->pmem_map[current_index+current_block->count+next_block->count-1].start = current_index;

  283. current_block->count += next_block->count;

  284. current_block->pmem_chunk = next_block->pmem_chunk;

  285. next_block->pmem_chunk = NULL;

  286. }

  287. // 如果後一塊記憶體不是空閒的,在pfree_mem_chunk中增加一個chunk

  288. else

  289. {

  290. memory_chunk* new_chunk = front_pop(pMem->pfree_mem_chunk_pool);

  291. new_chunk->pfree_mem_addr = current_block;

  292. current_block->pmem_chunk = new_chunk;

  293. push_back(pMem->pfree_mem_chunk, new_chunk);

  294. pMem->mem_map_pool_count--;

  295. pMem->free_mem_chunk_count++;

  296. }

  297. }

  298. else

  299. {

  300. memory_chunk* new_chunk = front_pop(pMem->pfree_mem_chunk_pool);

  301. new_chunk->pfree_mem_addr = current_block;

  302. current_block->pmem_chunk = new_chunk;

  303. push_back(pMem->pfree_mem_chunk, new_chunk);

  304. pMem->mem_map_pool_count--;

  305. pMem->free_mem_chunk_count++;

  306. }

  307. }

  308.  
  309. // 最後一個

  310. else if (current_index == pMem->mem_block_count-1)

  311. {

  312. if (current_block->count < pMem->mem_block_count)

  313. {

  314. pre_block = &(pMem->pmem_map[current_index-1]);

  315. size_t index = pre_block->count;

  316. pre_block = &(pMem->pmem_map[index]);

  317.  
  318. // 如果前一個記憶體塊是空閒的,合併

  319. if (pre_block->pmem_chunk != NULL)

  320. {

  321. pMem->pmem_map[current_index+current_block->count-1].start = current_index - pre_block->count;

  322. pre_block->count += current_block->count;

  323. current_block->pmem_chunk = NULL;

  324. }

  325. // 如果前一塊記憶體不是空閒的,在pfree_mem_chunk中增加一個chunk

  326. else

  327. {

  328. memory_chunk* new_chunk = front_pop(pMem->pfree_mem_chunk_pool);

  329. new_chunk->pfree_mem_addr = current_block;

  330. current_block->pmem_chunk = new_chunk;

  331. push_back(pMem->pfree_mem_chunk, new_chunk);

  332. pMem->mem_map_pool_count--;

  333. pMem->free_mem_chunk_count++;

  334. }

  335. }

  336. else

  337. {

  338. memory_chunk* new_chunk = front_pop(pMem->pfree_mem_chunk_pool);

  339. new_chunk->pfree_mem_addr = current_block;

  340. current_block->pmem_chunk = new_chunk;

  341. push_back(pMem->pfree_mem_chunk, new_chunk);

  342. pMem->mem_map_pool_count--;

  343. pMem->free_mem_chunk_count++;

  344. }

  345. }

  346. else

  347. {

  348. next_block = &(pMem->pmem_map[current_index+current_block->count]);

  349. pre_block = &(pMem->pmem_map[current_index-1]);

  350. size_t index = pre_block->start;

  351. pre_block = &(pMem->pmem_map[index]);

  352. bool is_back_merge = false;

  353. if (next_block->pmem_chunk == NULL && pre_block->pmem_chunk == NULL)

  354. {

  355. memory_chunk* new_chunk = front_pop(pMem->pfree_mem_chunk_pool);

  356. new_chunk->pfree_mem_addr = current_block;

  357. current_block->pmem_chunk = new_chunk;

  358. push_back(pMem->pfree_mem_chunk, new_chunk);

  359. pMem->mem_map_pool_count--;

  360. pMem->free_mem_chunk_count++;

  361. }

  362. // 後一個記憶體塊

  363. if (next_block->pmem_chunk != NULL)

  364. {

  365. next_block->pmem_chunk->pfree_mem_addr = current_block;

  366. pMem->pmem_map[current_index+current_block->count+next_block->count-1].start = current_index;

  367. current_block->count += next_block->count;

  368. current_block->pmem_chunk = next_block->pmem_chunk;

  369. next_block->pmem_chunk = NULL;

  370. is_back_merge = true;

  371. }

  372. // 前一個記憶體塊

  373. if (pre_block->pmem_chunk != NULL)

  374. {

  375. pMem->pmem_map[current_index+current_block->count-1].start = current_index - pre_block->count;

  376. pre_block->count += current_block->count;

  377. if (is_back_merge)

  378. {

  379. delete_chunk(pMem->pfree_mem_chunk, current_block->pmem_chunk);

  380. push_front(pMem->pfree_mem_chunk_pool, current_block->pmem_chunk);

  381. pMem->free_mem_chunk_count--;

  382. pMem->mem_map_pool_count++;

  383. }

  384. current_block->pmem_chunk = NULL;

  385. }

  386. }

  387. pMem->mem_used_size -= size;

  388. }

MemoryPoolTest.cpp

 
  1. // memory pool test.cpp : Defines the entry point for the console application.

  2. #include <tchar.h>

  3. #include "MemoryPool.h"

  4. #include <iostream>

  5. #include <windows.h>

  6. #include <vector>

  7. #include <time.h>

  8. #include <math.h>

  9. #include <fstream>

  10. using namespace std;

  11. int break_time = 0;

  12. // 檢測記憶體池相關引數

  13. void check_mem_pool(int& max_chunk_size, int& free_chunk_count, int& min_chunk_size, int& total_free_mem, MEMORYPOOL* mem_pool)

  14. {

  15. memory_chunk* head = mem_pool->pfree_mem_chunk;

  16. memory_chunk* tmp = head;

  17. free_chunk_count = 0;

  18. total_free_mem = 0;

  19. max_chunk_size = 0;

  20. min_chunk_size = 500*1024*1024;

  21. if (head == NULL)

  22. {

  23. min_chunk_size = 0;

  24. return;

  25. }

  26. while (tmp->next != head)

  27. {

  28. free_chunk_count++;

  29. total_free_mem += tmp->pfree_mem_addr->count * MINUNITSIZE;

  30. if (tmp->pfree_mem_addr->count * MINUNITSIZE > max_chunk_size )

  31. {

  32. max_chunk_size = tmp->pfree_mem_addr->count * MINUNITSIZE;

  33. }

  34. if (tmp->pfree_mem_addr->count * MINUNITSIZE < min_chunk_size)

  35. {

  36. min_chunk_size = tmp->pfree_mem_addr->count * MINUNITSIZE;

  37. }

  38. tmp = tmp->next;

  39. }

  40. free_chunk_count++;

  41. total_free_mem += tmp->pfree_mem_addr->count * MINUNITSIZE;

  42. if (tmp->pfree_mem_addr->count * MINUNITSIZE > max_chunk_size )

  43. {

  44. max_chunk_size = tmp->pfree_mem_addr->count * MINUNITSIZE;

  45. }

  46. if (tmp->pfree_mem_addr->count * MINUNITSIZE < min_chunk_size)

  47. {

  48. min_chunk_size = tmp->pfree_mem_addr->count * MINUNITSIZE;

  49. }

  50. }

  51. // 申請後緊接著釋放

  52. double test_mem_pool_perf_1(PMEMORYPOOL mem_pool, int iter, int* sizes)

  53. {

  54. cout << "*********************test_mem_pool_perf_1*********************" << endl;

  55. LARGE_INTEGER litmp;

  56. LONGLONG QPart1, QPart2;

  57. double t;

  58. double dfMinus, dfFreq;

  59. QueryPerformanceFrequency(&litmp);

  60. dfFreq = (double)litmp.QuadPart;// 獲得計數器的時鐘頻率

  61. QueryPerformanceCounter(&litmp);

  62. QPart1 = litmp.QuadPart;// 獲得初始值

  63. for (int i = 0; i < iter; i++)

  64. {

  65. void *p = GetMemory(sizes[i], mem_pool);

  66. if (p == NULL)

  67. {

  68. cout << "break @ iterator = " << i << " / " << iter << ", need memory " << sizes[i] << " Byte" << endl;

  69. cout << "total memory is: " << mem_pool->size << " Byte" << endl;

  70. cout << "memory used is: " << mem_pool->mem_used_size << " Byte" << endl;

  71. cout << "memory left is: " << mem_pool->size - mem_pool->mem_used_size << endl << endl;

  72. int max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem;

  73. check_mem_pool(max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem, mem_pool);

  74. cout << "check memory pool result:" << endl;

  75. cout << "free_chunk_count: " << free_chunk_count << endl

  76. << "total_free_mem: " << total_free_mem << endl

  77. << "max_chunk_size: " << max_chunk_size << endl

  78. << "min_chunk_size: " << min_chunk_size << endl;

  79. break;

  80. }

  81. FreeMemory(p, mem_pool);

  82. }

  83. QueryPerformanceCounter(&litmp);

  84. QPart2 = litmp.QuadPart;//獲得中止值

  85. dfMinus = (double)(QPart2-QPart1);

  86. t = dfMinus / dfFreq;// 獲得對應的時間值,單位為秒

  87. cout << "test_mem_pool_perf_1: iter = " << iter << endl;

  88. cout << "time: " << t << endl;

  89. cout << "*********************test_mem_pool_perf_1*********************" << endl << endl << endl;

  90. return t;

  91. }

  92. double test_std_perf_1(int iter, int* sizes)

  93. {

  94. cout << "*********************test_std_perf_1*********************" << endl;

  95. LARGE_INTEGER litmp;

  96. LONGLONG QPart1, QPart2;

  97. double t;

  98. double dfMinus, dfFreq;

  99. QueryPerformanceFrequency(&litmp);

  100. dfFreq = (double)litmp.QuadPart;// 獲得計數器的時鐘頻率

  101. QueryPerformanceCounter(&litmp);

  102. QPart1 = litmp.QuadPart;// 獲得初始值

  103. for (int i = 0; i < iter; i++)

  104. {

  105. void *p = malloc(sizes[i]);

  106. if (p == NULL)

  107. {

  108. cout << "break @ iterator = " << i << " / " << iter << ", need memory " << sizes[i] << " Byte" << endl;

  109. break;

  110. }

  111. free(p);

  112. }

  113. QueryPerformanceCounter(&litmp);

  114. QPart2 = litmp.QuadPart;//獲得中止值

  115. dfMinus = (double)(QPart2-QPart1);

  116. t = dfMinus / dfFreq;// 獲得對應的時間值,單位為秒

  117. cout << "test_std_perf_1: iter = " << iter << endl;

  118. cout << "time: " << t << endl;

  119. cout << "*********************test_std_perf_1*********************" << endl << endl << endl;

  120. return t;

  121. }

  122. // 連續申請iter/2次,然後釋放所有申請記憶體;再重複一次

  123. double test_mem_pool_perf_2(PMEMORYPOOL mem_pool, int iter, int size)

  124. {

  125. cout << "*********************test_mem_pool_perf_2*********************" << endl;

  126. LARGE_INTEGER litmp;

  127. LONGLONG QPart1, QPart2;

  128. double t;

  129. double dfMinus, dfFreq;

  130. QueryPerformanceFrequency(&litmp);

  131. dfFreq = (double)litmp.QuadPart;// 獲得計數器的時鐘頻率

  132. QueryPerformanceCounter(&litmp);

  133. QPart1 = litmp.QuadPart;// 獲得初始值

  134. void **p = new void*[iter];

  135. if (p == NULL)

  136. {

  137. cout << "new faild" << endl;

  138. return -1;

  139. }

  140. int count = 0;

  141. for (int i = 0; i < iter/2; i++)

  142. {

  143. p[i] = GetMemory(size, mem_pool);

  144. if (p[i] == NULL)

  145. {

  146. cout << "break @ iterator = " << i << " / " << iter << ", need memory " << size << " Byte" << endl;

  147. cout << "total memory is: " << mem_pool->size << " Byte" << endl;

  148. cout << "memory used is: " << mem_pool->mem_used_size << " Byte" << endl;

  149. cout << "memory left is: " << mem_pool->size - mem_pool->mem_used_size << endl << endl;

  150. int max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem;

  151. check_mem_pool(max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem, mem_pool);

  152. cout << "check memory pool result:" << endl;

  153. cout << "free_chunk_count: " << free_chunk_count << endl

  154. << "total_free_mem: " << total_free_mem << endl

  155. << "max_chunk_size: " << max_chunk_size << endl

  156. << "min_chunk_size: " << min_chunk_size << endl;

  157. break;

  158. }

  159. count++;

  160. }

  161. for (int i = 0; i < count; i++)

  162. {

  163. FreeMemory(p[i], mem_pool);

  164. }

  165. count = 0;

  166. for (int i = 0; i < iter/2; i++)

  167. {

  168. p[i] = GetMemory(size, mem_pool);

  169. if (p[i] == NULL)

  170. {

  171. cout << "break @ iterator = " << i << " / " << iter << ", need memory " << size << " Byte" << endl;

  172. cout << "total memory is: " << mem_pool->size << " Byte" << endl;

  173. cout << "memory used is: " << mem_pool->mem_used_size << " Byte" << endl;

  174. cout << "memory left is: " << mem_pool->size - mem_pool->mem_used_size << endl << endl;

  175.  
  176. int max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem;

  177. check_mem_pool(max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem, mem_pool);

  178. cout << "check memory pool result:" << endl;

  179. cout << "free_chunk_count: " << free_chunk_count << endl

  180. << "total_free_mem: " << total_free_mem << endl

  181. << "max_chunk_size: " << max_chunk_size << endl

  182. << "min_chunk_size: " << min_chunk_size << endl;

  183. break;

  184. }

  185. count++;

  186. }

  187. for (int i = 0; i < count; i++)

  188. {

  189. if (p[i] == NULL)

  190. {

  191. cout << i << endl;

  192. break;

  193. }

  194. FreeMemory(p[i], mem_pool);

  195. }

  196. QueryPerformanceCounter(&litmp);

  197. QPart2 = litmp.QuadPart;//獲得中止值

  198. dfMinus = (double)(QPart2-QPart1);

  199. t = dfMinus / dfFreq;// 獲得對應的時間值,單位為秒

  200. cout << "test_mem_pool_perf_2: iter = " << iter << endl;

  201. cout << "time: " << t << endl;

  202. delete []p;

  203. cout << "*********************test_mem_pool_perf_2*********************" << endl << endl << endl;

  204. return t;

  205. }

  206. // 連續申請inner_iter次,釋放;重複iter/inner_iter次

  207. double test_mem_pool_perf_3(PMEMORYPOOL mem_pool, int iter, int size)

  208. {

  209. cout << "*********************test_mem_pool_perf_3*********************" << endl;

  210. int inner_iter = 10;

  211. void **p = new void*[inner_iter];

  212. if (p == NULL)

  213. {

  214. cout << "new faild" << endl;

  215. return -1;

  216. }

  217. LARGE_INTEGER litmp;

  218. LONGLONG QPart1, QPart2, start, finish;

  219. double t;

  220. double dfMinus, dfFreq;

  221. QueryPerformanceFrequency(&litmp);

  222. dfFreq = (double)litmp.QuadPart;// 獲得計數器的時鐘頻率

  223. QueryPerformanceCounter(&litmp);

  224. QPart1 = litmp.QuadPart;// 獲得初始值

  225. for (int k = 0; k < iter / inner_iter; k++)

  226. {

  227. int j = 0;

  228. for (j = 0; j < inner_iter; j++)

  229. {

  230. p[j] = GetMemory(size, mem_pool);

  231. if (p[j] == NULL)

  232. {

  233. cout << "break @ iterator = " << j << " / " << iter << ", need memory " << size << " Byte" << endl;

  234. cout << "total memory is: " << mem_pool->size << " Byte" << endl;

  235. cout << "memory used is: " << mem_pool->mem_used_size << " Byte" << endl;

  236. cout << "memory left is: " << mem_pool->size - mem_pool->mem_used_size << endl << endl;

  237. int max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem;

  238. check_mem_pool(max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem, mem_pool);

  239. cout << "check memory pool result:" << endl;

  240. cout << "free_chunk_count: " << free_chunk_count << endl

  241. << "total_free_mem: " << total_free_mem << endl

  242. << "max_chunk_size: " << max_chunk_size << endl

  243. << "min_chunk_size: " << min_chunk_size << endl;

  244. break;

  245. }

  246. }

  247. for (int i = 0; i < j; i++)

  248. {

  249. FreeMemory(p[i], mem_pool);

  250. }

  251. }

  252. QueryPerformanceCounter(&litmp);

  253. QPart2 = litmp.QuadPart;//獲得中止值

  254. dfMinus = (double)(QPart2-QPart1);

  255. t = dfMinus / dfFreq;// 獲得對應的時間值,單位為秒

  256. cout << "test_mem_pool_perf_3: iter = " << iter << endl;

  257. cout << "time: " << t << endl;

  258. cout << "*********************test_mem_pool_perf_3*********************" << endl << endl << endl;

  259. return t;

  260. }

  261. // 隨機記憶體大小,隨機釋放操作

  262. double test_mem_pool_perf_rand(PMEMORYPOOL mem_pool, int iter, int* sizes, int* instruction)

  263. {

  264. cout << "-----------------------test_mem_pool_perf_rand----------------------- "<< endl;

  265. void** p = new void*[iter];

  266. if (p == NULL)

  267. {

  268. cout << "new failed" << endl;

  269. return -1;

  270. }

  271. LARGE_INTEGER litmp, gftime;

  272. LONGLONG QPart1, QPart2, start, finish;

  273. double t, GetMemory_time, FreeMemory_time;

  274. double dfMinus, dfFreq;

  275. QueryPerformanceFrequency(&litmp);

  276. dfFreq = (double)litmp.QuadPart;// 獲得計數器的時鐘頻率

  277. QueryPerformanceCounter(&litmp);

  278. QPart1 = litmp.QuadPart;// 獲得初始值

  279. int index = 0;

  280. int size;

  281. int free_tmp = 0;

  282. double seach_time;

  283. for (int i = 0; i < iter; i++)

  284. {

  285. size = sizes[i];

  286. p[index++] = GetMemory(size, mem_pool);

  287. if (p[index-1] == NULL)

  288. {

  289. break_time++;

  290. cout << "break @ iterator = " << i << " / " << iter << ", need memory " << size << " Byte" << endl;

  291. cout << "total memory is: " << mem_pool->size << " Byte" << endl;

  292. cout << "memory used is: " << mem_pool->mem_used_size << " Byte" << endl;

  293. cout << "memory left is: " << mem_pool->size - mem_pool->mem_used_size << endl << endl;

  294. int max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem;

  295. check_mem_pool(max_chunk_size, free_chunk_count, min_chunk_size, total_free_mem, mem_pool);

  296. cout << "check memory pool result:" << endl;

  297. cout << "free_chunk_count: " << free_chunk_count << endl

  298. << "total_free_mem: " << total_free_mem << endl

  299. << "max_chunk_size: " << max_chunk_size << endl

  300. << "min_chunk_size: " << min_chunk_size << endl;

  301. break;

  302. }

  303.  
  304. if (instruction[i] == 1)

  305. {

  306. FreeMemory(p[--index], mem_pool);

  307. }

  308. }