飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 1987|回复: 0

采用栈实现简单的对象池

[复制链接]
  • TA的每日心情
    开心
    2023-4-6 10:07
  • 签到天数: 23 天

    [LV.4]偶尔看看III

    发表于 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[nObjSize * nObjCount + 1];
        memset(m_pPoolHeader, 0, nObjSize * nObjCount + 1);

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

        // 分配状态数组
        try
        {
            m_pBucketState = new unsigned char[nObjCount];
            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[m_nObjSize];
            fprintf(stderr, "alloc from heap: %p.\n", ptr);
            return ptr;
        }

        // 从队尾拿一个空间的对象块(bucket)
        unsigned char* ptr = (unsigned char *)m_pBucket[m_nStackTop--];
        unsigned int idx = (ptr - m_pPoolHeader) / m_nObjSize;
        m_pBucketState[idx] = 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[idx]) // 回收之前先判断一下是否已经回收
            {
                m_pBucket[++m_nStackTop] = (unsigned int)ptr;
                m_pBucketState[idx] = 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[100];
    };
    class B
    {
        OBJECT_POOL_DECLARE(); // 声明对象池
    private:
        int array[100];
    };

    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[nArraySize];
            for (int j=0; j<nArraySize; j++)
            {
                p[j] = new B;
            }
            for (int j=0; j<nArraySize; j++)
            {
                delete p[j];
            }
        }
        end2 = time(0);
       
        begin1 = time(0);
        for (unsigned int i=0; i<nLoopCount; i++)
        {
            A* p[nArraySize];
            for (int j=0; j<nArraySize; j++)
            {
                p[j] = new A;            
            }
            for (int j=0; j<nArraySize; j++)
            {
                delete p[j];
            }
        }
        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
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表