内存管理器(内存池)

讨论QQ群:135202158

 

在一些应用场合,比如一个繁忙的服务器程序中,服务器频繁地接受并处理用户请求,如果每次处理都需要从系统动态地申请和释放内存,由于此操作开销较大,会加大处理时延;另一方面,此开销造成的累积效应也是很大的。

对此我们可以举一个生活中的例子:假设一个烟鬼一天抽10包烟(这有点太多了,假设啊),如果他每次去商店只买一包烟,他一天就要往商店跑10次,很麻烦;如果他一次买一条(10 包)放着,那么他一天之内就可以不用再跑商店了,想抽烟的时候,直接拿抽剩下的就行了。

这种预先分配所有所需资源、在运行时直接调配的思想,都可以称为池化策略,比如内存池和线程池。其实上面烟鬼买烟的例子,举的并不是特别恰当。因为池中的资源(内存或线程),在使用完之后,是可以回收的,而烟抽完就没有了。

这篇随笔主要讲内存池,线程池见http://www.cnblogs.com/zzqcn/p/3625452.html

 

要实现内存池,除了预先分配一块大内存块之外,我们还需要设计一个用来记录当前内存使用情况的数据结构,它至少需要记录以下信息:

  1. 某个内存块是否可用
  2. 内存块的起始地址
  3. 内存块的大小

我们可以设计一个双向循环链表来保存内存使用信息,而表中每一个结点如下图所示:

如果用C++语言表示,则如下(mbl:memory block list):

struct mblnode
{
    mblnode*    left;
    mblnode*    right;
    bool        tag;
    size_t      offset;
    size_t      size;
};

 

另外,还需要制订内存分配和回收的策略。这些策略包括:

  1. 从哪个地方开始分配
  2. 用户申请多少,就分配多少,还是有一个分配最小值
  3. 回收某个内存块之后,如何和其他空闲块合并成大的空闲块
  4. 回收内存块之后,下次分配的位置是否变化

讨论分配和策略之前,我们先设定一个当前指针p,它指向一个可用块,每次内存分配都从这个可用块进行。

对于1:每次分配后,都将p指向已分配块的下一个可用内存块;
对于2:设定一个最小值MINSIZE,当用户申请的内存块大小小于MINSIZE时,就分配MINSIZE大小的内存块给用户;
对于3:回收某块内存后,需要根据多种不同情况,与周围的可用块进行合并,形成更大的可用块;
对于4:回收内存后,应比较新合并的可用块的大小和p指向的内存块的大小,并将p指向更大的内存块。

上述分配回收策略,都减小了内存池中的碎片,提升分配效率。

 

下面用图演示一下分配过程。假设内存池大小为12,绿色代表空闲块,红色代表已用块,p为当前分配指针,下面的数据结构是我们的双向循环链表,链表结点中第1项是是否可用的标志,打勾表示可用,打x表示已用,第2项表示内存块起始地址,第3项表示此块的大小。下图表示从完全空闲的内存池连续分配大小为2、5的两块内存的情况:

 

 下图表示回收一块内存时与周围空闲块合并的多种情况,每一种情况都需要小心地编码:

 

完整C++代码:

  1 /*
  2  * 内存池实现 - 使用双循环链表.
  3  * Author: 赵子清
  4  * Blog: http://www.cnblogs.com/zzqcn
  5  **/
  6 
  7 
  8 #include <cstdlib>
  9 #include <cstdio>
 10 
 11 
 12 struct mblnode
 13 {
 14     mblnode*    left;
 15     mblnode*    right;
 16     bool        tag;
 17     size_t      offset;
 18     size_t      size;
 19 };
 20 
 21 
 22 #define     MAXBUFF     12
 23 #define     MINSIZE     2
 24 
 25 char        BUFF[MAXBUFF];
 26 mblnode*    mbl = NULL;
 27 
 28 int     my_init();
 29 int     my_deinit();
 30 char*   my_new(size_t _n);
 31 int     my_del(char* _p);
 32 void    my_merge_nil  (mblnode* _p);
 33 void    my_merge_left (mblnode* _p);
 34 void    my_merge_right(mblnode* _p);
 35 void    my_merge_both (mblnode* _p);
 36 int     my_print_mbl();
 37 
 38 
 39 int  main(int argc, char** argv)
 40 {
 41     my_init();
 42 
 43     // new
 44     char* p = my_new(2);
 45     if (p != NULL)
 46     {
 47         p[0] = 'a';
 48         p[1] = 'b';
 49     }
 50     my_print_mbl();
 51 
 52     // new
 53     char* p2 = my_new(5);
 54     if (p2 != NULL)
 55     {
 56         p2[0] = 'c';
 57         p2[1] = 'd';
 58         p2[2] = 'e';
 59         p2[3] = 'f';
 60         p2[4] = 'g';
 61     }
 62     my_print_mbl();
 63 
 64     // new
 65     char* p3 = my_new(2);
 66     if (p3 != NULL)
 67     {
 68         p3[0] = 'h';
 69         p3[1] = 'i';
 70     }
 71     my_print_mbl();
 72 
 73     my_del(p2);     my_print_mbl();
 74     my_del(p);      my_print_mbl();
 75     my_del(p3);     my_print_mbl();
 76 
 77     my_deinit();
 78     
 79     system("PAUSE");
 80     return 0;
 81 }
 82 
 83 
 84 int  my_init()
 85 {
 86     if (mbl != NULL)
 87         my_deinit();
 88 
 89     mblnode* p = new mblnode;
 90     p->left = p->right = p;
 91     p->offset = 0;
 92     p->size = MAXBUFF;
 93     p->tag = false;
 94 
 95     mbl = p;
 96 
 97     return 0;
 98 }
 99 
100 
101 int  my_deinit()
102 {
103     if (NULL == mbl)
104         return 0;
105 
106     mblnode*  p = NULL;
107     mblnode*  q = NULL;
108 
109     p = mbl;
110     do
111     {
112         q = p;
113         p = p->right;
114         delete q;   q = NULL;
115     } while (p != mbl);
116 
117     return 0;
118 }
119 
120 
121 char*  my_new(size_t _n)
122 {
123     mblnode*  p = NULL;
124     char*     ret = NULL;
125 
126     if (NULL == mbl)
127         return NULL;
128 
129     if (_n < MINSIZE)
130         _n = MINSIZE;
131 
132     for (p = mbl; p->right != mbl; p = p->right)
133     {
134         if (p->tag || p->size < _n)
135             continue;
136         else
137             break;
138     }
139 
140     if (NULL == p || p->size < _n)
141         return NULL;
142 
143     if (p->size > _n)
144     {
145         mblnode*  pnew = new mblnode;
146         p->left->right = pnew;
147         pnew->left  = p->left;
148         pnew->right = p;
149         pnew->offset = p->offset;
150         pnew->size = _n;
151         pnew->tag = true;
152 
153         p->size -= _n;
154         p->offset += _n;
155         p->left = pnew;
156 
157         mbl = p;
158         ret = BUFF + pnew->offset;
159     }
160     else if (p->size == _n)
161     {
162         p->tag = true;
163         
164         mbl = p;
165         ret = BUFF + p->offset;
166     }
167 
168     return ret;
169 }
170 
171 
172 int  my_del(char* _p)
173 {
174     if (NULL == _p || _p < BUFF || _p >= BUFF + MAXBUFF)
175         return -1;
176 
177     int  ret = -1;
178     mblnode*  p = NULL;
179     mblnode*  pcur = NULL;
180 
181     p = mbl;
182     do
183     {
184         if ((p->offset + BUFF) == _p)
185         {
186             pcur = p;
187             break;
188         }
189         p = p->right;
190     } while (p != mbl);
191    
192 
193     if (NULL == pcur)
194         return -1;
195 
196     /* left & right are all NOT free */
197     if (pcur->left->tag && pcur->right->tag)
198     {
199         my_merge_nil(pcur);
200         ret = 0;
201     }
202     /* left is free */
203     else if (!pcur->left->tag && pcur->right->tag)
204     {
205         if (pcur->offset != 0)
206             my_merge_left(pcur);
207         /* upper boundary */
208         else
209             my_merge_nil(pcur);
210 
211         ret = 0;
212     }
213     /* right is free */
214     else if (pcur->left->tag && !pcur->right->tag)
215     {
216         if (pcur->right->offset != 0)
217             my_merge_right(pcur);
218         /* lower boundary */
219         else
220             my_merge_nil(pcur);
221 
222         ret = 0;
223     }
224     /* left and right are all free */
225     else if (!pcur->left->tag && !pcur->right->tag)
226     {
227         //if (0 == pcur->left->offset)
228         if (0 == pcur->offset)
229             my_merge_right(pcur);
230         else if (0 == pcur->right->offset)
231             my_merge_left(pcur);
232         else
233             my_merge_both(pcur);
234         
235         ret = 0;
236     }
237 
238     return ret;
239 }
240 
241 
242 void  my_merge_nil(mblnode* _p)
243 {
244     _p->tag = false;
245     if (mbl->size < _p->size)
246         mbl = _p;
247 }
248 
249 void  my_merge_left(mblnode* _p)
250 {
251     _p->left->right = _p->right;
252     _p->right->left = _p->left;
253     _p->left->size += _p->size;
254 
255     if (mbl->size < _p->left->size)
256         mbl = _p->left;
257 
258     delete _p;    _p = NULL;
259 }
260 
261 void  my_merge_right(mblnode* _p)
262 {
263     _p->left->right = _p->right;
264     _p->right->left = _p->left;
265     _p->right->offset = _p->offset;
266     _p->right->size += _p->size;
267 
268     if (mbl->size < _p->right->size)
269         mbl = _p->right;
270 
271     delete _p;    _p = NULL;
272 }
273 
274 void  my_merge_both(mblnode* _p)
275 {
276     _p->left->right = _p->right->right;
277     _p->right->right->left = _p->left;
278 
279     _p->left->size += _p->size + _p->right->size;
280 
281     if (mbl->size < _p->left->size)
282         mbl = _p->left;
283 
284     delete _p->right;    _p->right = NULL;
285     delete _p;    _p = NULL;
286 }
287 
288 
289 int  my_print_mbl()
290 {
291     if (NULL == mbl)
292         return -1;
293 
294     mblnode* p = mbl;
295 
296     do
297     {
298         printf("[%c, %d, %d]\n",
299                 p->tag ? 'x' : 'v',
300                 p->offset,
301                 p->size);
302         p = p->right;
303     } while (p != mbl);
304 
305     printf("------------------\n");
306 
307     return 0;
308 }

 

输出结果:

[v, 2, 10]
[x, 0, 2]
------------------
[v, 7, 5]
[x, 0, 2]
[x, 2, 5]
------------------
[v, 9, 3]
[x, 0, 2]
[x, 2, 5]
[x, 7, 2]
------------------
[v, 2, 5]
[x, 7, 2]
[v, 9, 3]
[x, 0, 2]
------------------
[v, 0, 7]
[x, 7, 2]
[v, 9, 3]
------------------
[v, 0, 12]
------------------
请按任意键继续. . .

 

 

 

【参考资料】

《数据结构(C语言版)》,严蔚敏 吴伟民 编著,清华大学出版社。

posted @ 2014-03-26 15:37  赵子清  阅读(2550)  评论(0编辑  收藏  举报