简单内存池(Memory Pool)类的实现

简单内存池(Memory Pool)类的实现

作者:骄傲的猫

出处:http://blog.csdn.net/shardowm

一般的内存池的实现都是在申请一块大内存后,在这块内存中构造一个欲创建的对象的链表,然后通过对链表的管理实现对象内存的分配与回收。由于程序可以非常便捷的操作链表,所以这种方式实现的内存池可以大大提高程序分配和回收内存的效率。但是正是由于链表,给创建一个可通用的内存池类带来了很大的困难,而且在程序必须花费一定的时间来构建链表。解决这两个问题的关键是链表,那么是否可以在内存池中避免使用链表呢?答案是肯定的。

 下面的代码就是一个不使用链表的内存池类的声明。 

#pragma  once


#include
< new >
using   namespace  std;

class  Pool
{
public :
    
explicit  Pool(size_t block_size);
    
~ Pool( void );
    
void *  allocate(size_t size);                      // 分配内存函数
     void  free( void *  p, size_t n);                     // 回收内存函数
private :
    size_t    _block;                                   
// 被分配的内存块的大小
     static   const   int  MAX_BLOCKS  =   1024 ;               // 可创建对象数
     void *     stackPtr[MAX_BLOCKS];                       // 存放废弃的内存块地址的数组    
    int           top;
    
void *      base ;                                       // base、limit保存大内存块地址范围
     void *      limit;
    
void *      curr;                                       // 内存块中可分配内存的首地址
};

以下类的构造函数

Pool::Pool(size_t block_size)
: top(
0 )
base (NULL)
, limit(NULL)
{
    
base   =  :: operator   new (block_size  *  MAX_BLOCKS);
    limit 
=  static_cast < unsigned  char *> ( base +  block_size  *  MAX_BLOCKS;
    curr 
=   base ;
    _block 
=  block_size;
}

 在构造函数中我们申请了一块连续的大内存,并将它的地址的范围保存在base和limit两个指针中,并将该内存的起始地址赋给了curr指针。

为了便于理解Pool类,让我们先来看看负责回收内存的free函数是如何实现的。

void  Pool::free( void *  p, size_t n)
{
    
if  (n  !=  _block)
        ::
operator  delete(p);
    
else
        stackPtr[top
++ =  p;            // 将欲回收的内存的地址压入statckPtr堆栈
     return ;
}

在这个函数中,stackPtr和top实现了一个堆栈的功能,我们是将被回收的内存地址保存到了这个堆栈的末尾,而不像一般的内存池一样将被回收的内存插入到队列的最前面。

下面是分配内存的allocate函数


void *  Pool::allocate(size_t size)
{
    
if  (size  !=  _block)
        
return  :: operator   new (size);

    
// 在大内存中分配内存
     if  (curr  <  limit)
    {
        
void *  ptr  =  curr;
        curr 
=  static_cast < unsigned  char *> (curr)  +  size;
        
return  ptr;
    }
    
    
// 在被stackPtr堆栈中获得内存的地址
     if  (top  >   0 )
    {
        
return  stackPtr[ -- top];
    }
    
return  NULL;
}

在该函数中我们处理了两种可能出现的内存分配情况。第一种,直接在被分配的大内存中分配内存。我们说过在构造Pool类对象时我们将分配的大内存的起始地址赋给了curr指针,其实该指针时指向大内存中未被分配的内存的起始地址,通过返回curr获得分配的内存的地址,然后我们在curr上加上被分配内存的大小,使curr指向下一块将要被分配的内存的地址,直到curr=limit。第二种方式是在stackPtr堆栈中获得内存的地址,在讲free函数是我们说过stackPtr保存了被回收的内存地址,所以我们可以直接从堆栈上获取分配的内存的地址。

最后对我们实现内存池、普通的内存池和不使用内存池的情况进行测试,连续创建、释放一个只有一个int型数据成员的类的对象一亿次:这个内存池所需时间平均约:2375ms,普通的内存池平均约:2535ms,不使用内存池约:21100ms

测试机器:CPU: 讯驰II 2.0G,  内存:1G DDR533

-----------------------------------------------

由于写作经验有限难免在表达上有不清楚的地方和疏忽的地方(写文章向来是我的弱项,呵呵),还望大家见谅。同时热烈欢迎各位网友提出宝贵意见。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值