xingke 发表于 2007-11-1 10:50:08

采用栈实现简单的对象池

关键字 对象池
原作者姓名 易剑

介绍
本篇幅主要由四大部分组成,每个部分均为一独立文件,这四部分构成了对象池的完整实现:
ObjectPool.h:定义对象池接口
ObjectPool.cpp:实现对象池
x.cpp:用来测试对象池
Makefile:用来在GnuMake上编译

由于代码比较简单,以及时间上的问题,注释不多,请多多谅解!

正文
// Filename: ObjectPool.h
// Writed by yijian on 2005-06-03
// Defines the interface of object pool
#ifndef __OBJECT_POOL_H
#define __OBJECT_POOL_H

// 声明对象池宏,该宏只能放在类的定义中,具体请参见x.cpp中的示例
#define OBJECT_POOL_DECLARE() \
    private: \
      static CObjectPool m_ObjPool; \
    public: \
      static int init(unsigned int nObjCount); \
      static void fini(); \
      void* operator new(unsigned int); \
      void operator delete(void* p);

// 对象池实现宏,具体请参见x.cpp中的示例
#define OBJECT_POOL_IMPLEMENT(ClassName) \
    CObjectPool ClassName::m_ObjPool; \
    int ClassName::init(unsigned int nObjCount) \
    { \
      m_ObjPool.init(sizeof(ClassName), nObjCount); \
    } \
    void ClassName::fini() \
    { \
      m_ObjPool.fini(); \
    } \
    void* ClassName::operator new(unsigned int) \
    { \
      return m_ObjPool.alloc(); \
    } \
    void ClassName::operator delete(void* p) \
    { \
      m_ObjPool.free(p); \
    }

// 定义对象池类
class CObjectPool
{
public:
    CObjectPool();   
    // 用来初始化对象池,成功返回0,否则返回大于0的值
    // nObjSize:对象池中一个对象的字节数
    // nObjCount:对象池中可容纳的最大对象个数
    int init(unsigned int nObjSize, unsigned int nObjCount);
    // 用来释放初始化对象池时分配的资源
    void fini();
    // 从对象池中分配一个对象大小的内存块
    void* alloc();
    // 将一个对象大小的内存块回收到对象池中
    void free(void* p);

private:
    unsigned int   m_nObjSize;      // 对象池中对象的大小
    unsigned int   m_nObjCount;   // 对象池中对象的最大个数
    unsigned char* m_pPoolHeader;   // 对象池的内存首地址
    unsigned int*m_pBucket;       // 保存对象地址的数组
    unsigned char* m_pBucketState;// 对象状态,用来指示指定的对象内存块状态(已经分配或未分配)   
    int   m_nStackTop;            // 可用对象的位置
};

#endif // __OBJECT_POOL_H


// Filename: ObjectPool.cpp
// Writed by yijian on 2005-06-03
// Implements the object pool
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ObjectPool.h"

CObjectPool::CObjectPool()
:m_nObjSize(0),
m_nObjCount(0),
m_nStackTop(-1),
m_pPoolHeader(NULL),
m_pBucket(NULL),
m_pBucketState(NULL)
{
}

int CObjectPool::init(unsigned int nObjSize, unsigned int nObjCount)
{
    m_nObjSize = nObjSize;
    m_nObjCount = nObjCount;
   
    // 入口参数检查
    if (nObjSize < 1) return 1;
    if (nObjCount < 1) return 2;

    // 分配内存池
    m_pPoolHeader = new unsigned char;
    memset(m_pPoolHeader, 0, nObjSize * nObjCount + 1);

    // 分配保存对象地址的数组
    try
    {
      m_pBucket = new unsigned int;
    }
    catch (...)
    {
      delete []m_pPoolHeader;
      return 3;
    }

    // 分配状态数组
    try
    {
      m_pBucketState = new unsigned char;
      memset(m_pBucketState, 0, nObjCount);
    }
    catch (...)
    {
      delete []m_pBucket;
      delete []m_pPoolHeader;            
      return 4;
    }

    // 初始化栈顶位置
    m_nStackTop = nObjCount-1;
    // 循环存入每一个可用对象的地址到栈中
    for (unsigned int i=0; i<nObjCount; i++)
    {
      m_pBucket = (unsigned int)(m_pPoolHeader + (i * nObjSize));
    }
   
    return 0;
}
void CObjectPool::fini()
{
    delete []m_pBucketState;
    m_pBucketState = 0;

    delete []m_pBucket;
    m_pBucket = 0;

    delete []m_pPoolHeader;
    m_pPoolHeader = 0;
}

void* CObjectPool::alloc()
{
    if (-1 == m_nStackTop) // Not enough now, than alloc from heap.
    {         
      unsigned char* ptr = new unsigned char;
      fprintf(stderr, "alloc from heap: %p.\n", ptr);
      return ptr;
    }

    // 从队尾拿一个空间的对象块(bucket)
    unsigned char* ptr = (unsigned char *)m_pBucket;
    unsigned int idx = (ptr - m_pPoolHeader) / m_nObjSize;
    m_pBucketState = 1;
   
    return ptr;
}

void CObjectPool::free(void* p)
{
    unsigned char* ptr = (unsigned char *)p;
    // 先判断释放的是否为内存池中的
    if ( (ptr < m_pPoolHeader) || (ptr > m_pPoolHeader+m_nObjSize * m_nObjCount) )
    {
      delete []ptr;
      fprintf(stderr, "*free from heap: %p.\n", ptr);
    }
    else
    {
      // 即使ptr在对象池的范围内,也不一定就是对的,这里做一下判断
      if ((ptr - m_pPoolHeader) % m_nObjSize != 0)
      {
            fprintf(stderr, "free %p error.", ptr);
            return;
      }
      
      // 回收到队尾
      int idx = (ptr - m_pPoolHeader) / m_nObjSize;
      if (1 == m_pBucketState) // 回收之前先判断一下是否已经回收
      {
            m_pBucket[++m_nStackTop] = (unsigned int)ptr;
            m_pBucketState = 0;
      }
    }
}

// 下面是测试代码,主要是做性能测试
// Filename: x.cpp
// Writed by yijian on 2005-06-03
// This file is used to test CObjectPool performance
#include <time.h>
#include <stdio.h>
#include "ObjectPool.h"

class A
{
private:
    int array;
};
class B
{
    OBJECT_POOL_DECLARE(); // 声明对象池
private:
    int array;
};

OBJECT_POOL_IMPLEMENT(B);

int main()
{
   
    time_t begin1, end1;
    time_t begin2, end2;
    const unsigned int nPoolSize= 5000001;
    const unsigned int nArraySize = 10;
    const unsigned int nLoopCount = 500000;
   
    B::init(nPoolSize);

    begin2 = time(0);
    for (unsigned int i=0; i<nLoopCount; i++)
    {
      B* p;
      for (int j=0; j<nArraySize; j++)
      {
            p = new B;
      }
      for (int j=0; j<nArraySize; j++)
      {
            delete p;
      }
    }
    end2 = time(0);
   
    begin1 = time(0);
    for (unsigned int i=0; i<nLoopCount; i++)
    {
      A* p;
      for (int j=0; j<nArraySize; j++)
      {
            p = new A;            
      }
      for (int j=0; j<nArraySize; j++)
      {
            delete p;
      }
    }
    end1 = time(0);
   
    printf("Without object pool: %u\n", end1-begin1);
    printf("With    object pool: %u\n", end2-begin2);
   
    B::fini();
    return 0;
}

# Filename: ObjectPool.cpp
# Writed by yijian on 2005-06-03
# Make test codes
x: x.cpp ObjectPool.cpp ObjectPool.h
    g++ -g -o x x.cpp ObjectPool.cpp -I.
   
clean:
    rm -f x
页: [1]
查看完整版本: 采用栈实现简单的对象池