內存池的設計和實現總結(一)


  C/C++下內存管理是讓幾乎每一個程序員頭疼的問題,分配足夠的內存、追蹤內存的分配、在不需要的時候釋放內存——這個任務相當復雜。而直接使用系統調用malloc/free、new/delete進行內存分配和釋放,有以下弊端:

  1. 調用malloc/new,系統需要根據“最先匹配”、“最優匹配”或其他算法在內存空閑塊表中查找一塊空閑內存,調用free/delete,系統可能需要合並空閑內存塊,這些會產生額外開銷
  2. 頻繁使用時會產生大量內存碎片,從而降低程序運行效率
  3. 容易造成內存泄漏
  內存池則是在真正使用內存之前,先申請分配一定數量的、大小相等(一般情況下)的內存塊留作備用。當有新的內存需求時,就從內存池中分出一部分內存塊,若內存塊不夠再繼續申請新的內存。這樣做的一個顯著優點是,使得內存分配效率得到提升。
  本章先實現一個簡單的內存池(CSingleMemoryPools)。該內存池提供一定數量、大小相等的內存塊。該實例中,CSingleMemoryPools中的m_pMemoryFreeList負責對空閑內存塊進行管理,每個內存塊以_MemoryBlock類進行管理,其中首部有4個字節的指針塊地址 + 4個字節的list表首地址 + 4位驗證碼,然后才是分配的內存。
 1 #pragma once 
 2 
 3 //開發一個簡單的內存池,用於內存管理。 
 4 
 5 #include <stdio.h> 
 6 #include <stdlib.h> 
 7 #include <list>
 8 #include "ThreadLock.h" 
 9 
10 #define MAX_MEMORYHEAD_SIZE 12         //4個字節的指針塊地址 + 4個字節的List表首地址 + 4位驗證碼 
11 #define MAGIC_CODE          0xFFFFFF   //驗證碼 
12 #define MEMORY_BUFFER_SIZE  1024       //該簡單的內存池,提供1024字節大小的內存塊
13 #define UINT32 unsigned int 
14 
15 struct _MemoryBlock  //內存塊的結構,12字節head+內存空間
16 { 
17     void*         m_pBrick; 
18     _MemoryBlock()
19     { 
20         m_pBrick  = NULL;
21     }; 
22 }; 
23 
24 
25 class CSingleMemoryPools 
26 { 
27 public: 
28     static CSingleMemoryPools& Instance() 
29     { 
30         if(m_pMemoryPools == NULL) 
31         { 
32             m_pMemoryPools = new CSingleMemoryPools(); 
33         } 
34 
35         return *m_pMemoryPools; 
36     } 
37 
38 public: 
39     ~CSingleMemoryPools(void); 
40 
41     void* GetBuff();
42     bool DelBuff(void* pBuff); 
43     void DisplayMemoryList(); 
44 
45 private: 
46     CSingleMemoryPools(void); 
47     void Close(); 
48     void* SetMemoryHead(void* pBuff, std::list<_MemoryBlock*>* pList, _MemoryBlock* pBlock); 
49     void* GetMemoryHead(void* pBuff); 
50     bool GetHeadMemoryBlock(void* pBuff, std::list<_MemoryBlock*>*& pList, _MemoryBlock*& pBlock); 
51 
52 private: 
53     static CSingleMemoryPools* m_pMemoryPools; 
54     std::list<_MemoryBlock*> m_pMemoryFreeList;       //自由的內存塊list
55     CThreadLock          m_ThreadLock;
56 }; 
  1 #include "SingleMemoryPools.h" 
  2 #include <iostream>
  3 
  4 CSingleMemoryPools* CSingleMemoryPools::m_pMemoryPools = NULL; 
  5 CSingleMemoryPools::CSingleMemoryPools(void) 
  6 { 
  7 
  8 } 
  9 
 10 CSingleMemoryPools::~CSingleMemoryPools(void) 
 11 { 
 12     Close(); 
 13 } 
 14 
 15 
 16 void CSingleMemoryPools::Close() 
 17 { 
 18     //添加線程安全 
 19     CAutoLock autolock(&m_ThreadLock); 
 20 
 21     //刪除所有已經歸還的內存塊,
 22     //注:這個簡單的內存池功能,關閉功能必須在所有分配出去的內存塊都還回來之后才可以Close 
 23 
 24     std::list<_MemoryBlock*>::iterator itor = m_pMemoryFreeList.begin();
 25     while(itor != m_pMemoryFreeList.end())
 26     {
 27         free((*itor)->m_pBrick); 
 28         m_pMemoryFreeList.erase(itor);
 29         //兼容linux環境,linux下沒有iterator erase( iterator _Where )方法, 有void erase( iterator _Where )方法
 30         itor = m_pMemoryFreeList.begin();
 31     }
 32 } 
 33 
 34 void* CSingleMemoryPools::SetMemoryHead(void* pBuff, std::list<_MemoryBlock*>* pList, _MemoryBlock* pBlock) 
 35 { 
 36     //組成內存包頭 
 37     if(NULL == pBuff) 
 38     { 
 39         return NULL; 
 40     } 
 41 
 42     //因為一個long是4個字節,在linux和windows下都是一樣的。所以加起來是12個 
 43     UINT32* plData = (UINT32*)pBuff; 
 44 
 45     plData[0] = (UINT32)pList;         //內存List表首地址 
 46     plData[1] = (UINT32)pBlock;        //所在鏈表的地址 
 47     plData[2] = (UINT32)MAGIC_CODE;    //驗證碼 
 48 
 49     return &plData[3]; 
 50 } 
 51 
 52 void* CSingleMemoryPools::GetMemoryHead(void* pBuff) 
 53 { 
 54     if(NULL == pBuff) 
 55     { 
 56         return NULL; 
 57     } 
 58 
 59     long* plData = (long*)pBuff; 
 60     return &plData[3]; 
 61 } 
 62 
 63 bool CSingleMemoryPools::GetHeadMemoryBlock(void* pBuff, std::list<_MemoryBlock*>*& pList, _MemoryBlock*& pBlock) 
 64 { 
 65     char* szbuf = (char*)pBuff; 
 66     UINT32* plData = (UINT32*)(szbuf - MAX_MEMORYHEAD_SIZE); 
 67     if(plData[2] != (long)MAGIC_CODE) 
 68     { 
 69         return false; 
 70     } 
 71     else 
 72     { 
 73         pList  = (std::list<_MemoryBlock*>*)plData[0];   //內存List表首地址 
 74         pBlock = (_MemoryBlock*)plData[1];  //所在鏈表的地址 
 75 
 76         return true; 
 77     } 
 78 
 79 } 
 80 
 81 void* CSingleMemoryPools::GetBuff() 
 82 { 
 83     //添加線程安全 
 84     CAutoLock autolock(&m_ThreadLock); 
 85 
 86     void* pBuff = NULL; 
 87 
 88     //判斷是否有空閑的內存塊。 
 89     if(m_pMemoryFreeList.empty()) 
 90     { 
 91         //申請內存塊空間
 92         pBuff = malloc(MEMORY_BUFFER_SIZE + MAX_MEMORYHEAD_SIZE); 
 93         memcpy(pBuff,0,MEMORY_BUFFER_SIZE + MAX_MEMORYHEAD_SIZE);
 94         if(NULL == pBuff) 
 95         { 
 96             //printf_s("[CSingleMemoryPools::GetBuff] pBuff malloc = NULL.\n"); 
 97             return NULL; 
 98         } 
 99 
100         //新建一個內存塊單元
101         _MemoryBlock* pMemoryUsed = new _MemoryBlock(); 
102         if(NULL == pMemoryUsed) 
103         { 
104             //printf_s("[CSingleMemoryPools::GetBuff] pMemoryBrick new = NULL.\n"); 
105             delete pBuff; 
106             return NULL; 
107         } 
108 
109         pMemoryUsed->m_pBrick = pBuff; 
110         return SetMemoryHead(pBuff, &m_pMemoryFreeList, pMemoryUsed); 
111     } 
112 
113     //已有空余內存塊,由於內存塊頭部已經初始化過了,這邊無須再初始化,直接扔出來就可以了
114     _MemoryBlock* pBlockBuff = (m_pMemoryFreeList.front());
115     m_pMemoryFreeList.pop_front();
116     return GetMemoryHead(pBlockBuff->m_pBrick);
117 } 
118 
119 bool CSingleMemoryPools::DelBuff(void* pBuff) 
120 { 
121     //添加線程安全 
122     CAutoLock autolock(&m_ThreadLock); 
123 
124     _MemoryBlock* pMemoryUsed     = NULL; 
125     std::list<_MemoryBlock*>*  pCurrMemoryList = NULL; 
126 
127     if(false == GetHeadMemoryBlock(pBuff, pCurrMemoryList, pMemoryUsed)) 
128     {
129         return false; 
130     } 
131 
132     if(NULL != pMemoryUsed && pCurrMemoryList == &m_pMemoryFreeList ) 
133     { 
134         m_pMemoryFreeList.push_back(pMemoryUsed);
135         return true; 
136     } 
137 
138     //printf_s("[CSingleMemoryPools::DelBuff] pBuff = 0x%08x is not memoryPool.\n", pBuff); 
139     return false; 
140 } 
141 
142 void CSingleMemoryPools::DisplayMemoryList() 
143 { 
144     int nFreeCount = m_pMemoryFreeList.size();
145     printf_s("[CSingleMemoryPools::DisplayMemoryList] pMemoryFree nFreeCount = %d, Size = %d.\n", nFreeCount, MEMORY_BUFFER_SIZE * nFreeCount); 
146 } 
147 
148 // TODO: 在 STDAFX.H 中 
149 // 引用任何所需的附加頭文件,而不是在此文件中引用 
150 //#include "MemoryPools.h" 
151 
152 //重載New和Delete操作符 
153 inline void* operator new(size_t szBuff) 
154 { 
155     //注:由於這是一個簡單的內存池,大小固定,所以參數szBuff沒有用起來,后期會開發一個多層級大小的內存池
156     void* pBuff = CSingleMemoryPools::Instance().GetBuff(); 
157     //OUR_DEBUG((LM_ERROR, "[New] Size = %d Address = [0x%08x].!\n", (int)szBuff, pBuff)); 
158     return pBuff; 
159 } 
160 
161 inline void operator delete(void* p) 
162 { 
163     if(false == CSingleMemoryPools::Instance().DelBuff(p)) 
164     { 
165         //    OUR_DEBUG((LM_ERROR, "[Delete]*p = [0x%08x] false!\n", p)); 
166         //CSingleMemoryPools::Instance().DisplayMemoryList(p); 
167     } 
168     else 
169     { 
170         //OUR_DEBUG((LM_ERROR, "[Delete]*p = [0x%08x] OK!\n", p)); 
171     } 
172 } 
173 
174 inline void operator  delete[]( void * p ) 
175 { 
176     if(false == CSingleMemoryPools::Instance().DelBuff(p)) 
177     { 
178         //    OUR_DEBUG((LM_ERROR, "[Delete]*p = [0x%08x] false!\n", p)); 
179         //CSingleMemoryPools::Instance().DisplayMemoryList(p); 
180     } 
181     else 
182     { 
183         //OUR_DEBUG((LM_ERROR, "[Delete]*p = [0x%08x] OK!\n", p)); 
184     } 
185 } 

 

使用一個list來管理內存,相對於用兩個list(一個FreeList ,一個 Used List)的優點:更加簡潔,管理更加簡單;缺陷:無法知曉已經分配出去的內存塊。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM