代码改变世界

通用高效的c++内存池(特定类型)

2012-06-03 15:35  zhenjing  阅读(4456)  评论(3编辑  收藏  举报

通用高效内存池的设计要点:

1)快速分配;

2)快速回收;

3)空间利用率高。

4)类型独立(最好)。

不打算对比各种内存分配器的优劣,主要是介绍一最近实现的特定类型的通用高效C++内存池。

特点:

1)基于共享内存; -- 不会因为进程挂掉而丢失数据。

2)快速分配; -- 在内存池接近满时,效率不高。

3)快速回收;-- 常数。

4)空间利用率高 -- 利用bit标识内存块使用与否 (《C++设计新思维》的小对象分配器不占用额外空间!!

已知缺点:

1)在内存池接近满时,分配效率不高。

2)非类型独立。每一种类型需要一特定内存池。

3)非线程安全,需要使用者自行保证。

 

  1 #ifndef  __Memory_POOL__H__
  2 #define  __Memory_POOL__H__
  3 
  4 #include <string>
  5 #include <stdio.h>
  6 #include <stdlib.h>
  7 #include <time.h>
  8 #include <sys/time.h>
  9 #include <sys/shm.h>
 10 
 11 #include <bitstring.h>
 12 #include "utilfunc.h"
 13 
 14 
 15 template<class T>
 16 struct MemPoolHead
 17 {
 18     size_t iTotalSize;       //
 19     size_t iCurSize;         // 剩余空间数
 20     size_t iNextPos;        // 下一个可用位置,用于快速分配(循环分配)
 21     size_t iRecordLen;
 22 
 23     T      arrDatas[0];      // 作为占位符,初始化后有效
 24 
 25     MemPoolHead()
 26     {
 27         memset(this, 0, sizeof(MemPoolHead));
 28     }
 29 };
 30 
 31 template<class T>
 32 void PrintMemPoolHead(const MemPoolHead<T>& stHead) 
 33 { 
 34     printf("iTotalSize=%zu, iCurSize=%zu, iNextPos=%zu, iRecordLen=%zu\n",
 35             stHead.iTotalSize, stHead.iCurSize, stHead.iNextPos, stHead.iRecordLen);
 36 }
 37 
 38 template<class T>
 39 class MemoryPool
 40 {
 41     public:
 42         MemoryPool();
 43 
 44         ~MemoryPool();
 45 
 46         int Init(int ishmKey);   // for read exist data
 47         
 48         int Init(int ishmKey, const MemPoolHead<T>& stHeadInfo);  // for creating
 49         
 50         T*  GetPos();
 51 
 52         void DelPos(T* pdata);
 53  
 54         void PrintHead() const;
 55  
 56         int DeleteShm();
 57  
 58         int Reset();
 59         
 60         T* NextElem(size_t* pIndex) const;
 61 
 62 
 63         size_t Total() const;
 64         
 65         size_t Size() const;
 66 
 67         bool   Empty() const;
 68 
 69         bool   IsFull() const;
 70 
 71     private:
 72         MemoryPool(const MemoryPool&);
 73         MemoryPool& operator=(const MemoryPool&);
 74 
 75         int   m_ishmKey;
 76         MemPoolHead<T>*   m_datas;
 77 
 78         char*   m_usedbits;   // 标识特定内存块是否已使用
 79 };
 80 
 81 
 82 template<class T>
 83 MemoryPool<T>::MemoryPool()
 84 {
 85     m_ishmKey = -1;
 86     m_datas = NULL;
 87     m_usedbits = NULL;
 88 }
 89 
 90 template<class T>
 91 MemoryPool<T>::~MemoryPool()
 92 {
 93 
 94 }
 95 
 96 template<class T>
 97 int MemoryPool<T>::Init(int ishmKey, const MemPoolHead<T>& stHeadInfo)
 98 {
 99     if( stHeadInfo.iCurSize > stHeadInfo.iTotalSize || stHeadInfo.iRecordLen != sizeof(T)){
100         printf("Invalid parameters\n");
101         return -1;
102     }
103 
104     size_t size = sizeof(MemPoolHead<T>) + (stHeadInfo.iTotalSize) * sizeof(T) + (stHeadInfo.iTotalSize / 8 + 1);
105     
106     PrintMemPoolHead(stHeadInfo);
107     printf("Head len=%lu, Recode Len=%lu, shm Size=%lu\n", sizeof(MemPoolHead<T>), sizeof(T), size);
108 
109     int iCreate = false;
110     char* sShm = NULL;    
111     if (!(sShm = UTIL::GetShm(ishmKey,size,0666&(~IPC_CREAT)))) 
112     {
113         if (!(sShm = UTIL::GetShm(ishmKey,size,0666|IPC_CREAT))) 
114         {
115             printf("get shm error!\n");
116             return -2;
117         }
118         else 
119         {
120             iCreate = true;  
121 
122             memset(sShm, 0, size);
123         }
124     }
125 
126     m_datas = (MemPoolHead<T>*)sShm;   
127     m_ishmKey = ishmKey;
128 
129     m_usedbits = sShm + sizeof(MemPoolHead<T>) + (stHeadInfo.iTotalSize) * sizeof(T);
130 
131 
132     if( iCreate ){
133         memcpy(m_datas, &stHeadInfo, sizeof(stHeadInfo));
134 
135         m_datas->iCurSize = 0;
136         m_datas->iNextPos = 0;
137     }
138     else {
139         if( stHeadInfo.iTotalSize != m_datas->iTotalSize || stHeadInfo.iRecordLen != m_datas->iRecordLen )
140         {
141             printf("Memory head info is not matched!\n");
142             PrintHead();
143 
144             m_datas = NULL;
145             m_ishmKey = -1;
146             return -1;
147         }
148     }
149 
150     return 0;
151 }
152         
153 template<class T>
154 int MemoryPool<T>::Init(int ishmKey)
155 {
156     MemPoolHead<T> stHead;
157     char* sShm = NULL;
158     if (!(sShm = UTIL::GetShm(ishmKey, sizeof(MemPoolHead<T>), 0666&(~IPC_CREAT)))) {
159         return -1;
160     }
161 
162     memcpy(&stHead, sShm, sizeof(MemPoolHead<T>));
163 
164     return Init(ishmKey, stHead);
165 }
166 
167 template<class T>
168 T* MemoryPool<T>::GetPos()
169 {
170     if( NULL == m_datas || m_datas->iNextPos > m_datas->iTotalSize ){
171         printf("Something wrong in memory pool!\n");
172         return NULL;
173     }
174 
175     if( m_datas->iCurSize >= m_datas->iTotalSize ){
176         printf("Memory pool is full\n");
177         return NULL;
178     }
179 
180     T *pdata = NULL;
181 
182     while(1){
183 
184         if( m_datas->iNextPos >= m_datas->iTotalSize ){
185             m_datas->iNextPos = 0;
186         }
187         
188         if( bit_test(m_usedbits, m_datas->iNextPos) ){  // pos is used
189             m_datas->iNextPos++;
190             continue;
191         }
192         else{
193             bit_set(m_usedbits, m_datas->iNextPos);
194             
195             pdata = &m_datas->arrDatas[m_datas->iNextPos++];
196             m_datas->iCurSize ++;
197             break;
198         }
199     }
200     return pdata;
201 }
202 
203 template<class T>
204 void MemoryPool<T>::DelPos(T* pdata)
205 {
206     if( (char*)pdata >= (char*)m_datas + sizeof(MemPoolHead<T>) && (char*)pdata < m_usedbits) 
207     {
208         if( ((char*)pdata - ((char*)m_datas + sizeof(MemPoolHead<T>))) % sizeof(T) == 0){
209             size_t index = ((char*)pdata - ((char*)m_datas + sizeof(MemPoolHead<T>))) / sizeof(T);
210             
211             if( bit_test(m_usedbits, index) ){
212                 printf("delete pos: %p(%zu)\n", pdata, index); 
213 
214                 memset(pdata, 0, sizeof(T));
215             
216                 m_datas->iCurSize --;
217 
218                 bit_clear(m_usedbits, index);
219             }
220         }
221     }
222 }
223 
224 template<class T>
225 void MemoryPool<T>::PrintHead() const
226 {   
227     if( NULL == m_datas ) return;
228 
229     PrintMemPoolHead(*m_datas);
230 }
231 
232 template<class T>
233 int MemoryPool<T>::DeleteShm()
234 {
235     if( NULL == m_datas ) return 0;
236 
237     shmdt(m_datas);
238 
239     return UTIL::DeleteShm(m_ishmKey);
240 }
241         
242 template<class T>
243 int MemoryPool<T>::Reset()
244 {
245     if( NULL == m_datas ) return 0;
246     
247     size_t size = (m_datas->iTotalSize) * sizeof(T) + (m_datas->iTotalSize / 8 + 1);
248 
249     memset((char*)m_datas + sizeof(MemPoolHead<T>), 0, size);
250     m_datas->iCurSize = 0;
251     m_datas->iNextPos = 0;
252 
253     return 0;
254 }
255         
256 template<class T>
257 T* MemoryPool<T>::NextElem(size_t* pIndex) const
258 {
259     if( NULL == m_datas || NULL == pIndex ) return NULL;
260     
261     while( *pIndex < m_datas->iTotalSize ) 
262     {
263         size_t index = *pIndex;
264         if( bit_test(m_usedbits, index) )
265         {
266             *pIndex = index + 1;
267 
268             return &m_datas->arrDatas[index];
269         }
270         *pIndex = index + 1;
271     }
272 
273     return NULL;
274 }
275 
276 template<class T>
277 size_t MemoryPool<T>::Total() const
278 {
279     if( NULL == m_datas ) return 0;
280 
281     return m_datas->iTotalSize;
282 }
283 
284 template<class T>
285 size_t MemoryPool<T>::Size() const
286 {
287     if( NULL == m_datas ) return 0;
288 
289     return m_datas->iCurSize;
290 }
291 
292 template<class T>
293 bool   MemoryPool<T>::Empty() const
294 {
295     if( NULL == m_datas ) return false;
296 
297     return ( 0 == m_datas->iCurSize);
298 }
299 
300 template<class T>
301 bool   MemoryPool<T>::IsFull() const
302 {
303     if( NULL == m_datas ) return true;
304 
305     return (m_datas->iTotalSize == m_datas->iCurSize);
306 }
307 
308 #endif