自己做的一个固定大小对象内存池,效率大概为原始的new/delete的2倍

提升不高,不过好处是可以多次申请小对象,一次释放。(只适应于无动态申请资源的class)

vs2012测试情况如下:

 

 

 

 

// CHchFixLenMemPool.h
#pragma  once
#ifndef __CHchFixLenMemPool_H__
#define __CHchFixLenMemPool_H__
#include <exception>
#include <new>

typedef struct __HchFixLenMemPoolLinkNode
{
    __HchFixLenMemPoolLinkNode *m_next;
}SHchFixLenMemPoolLinkNode;

class CHchFixLenMemPool
{
public:
    CHchFixLenMemPool(size_t nFixLen, size_t nExpectObjectCnt = 0)
    { 
        if ( nFixLen < (sizeof(void *) > sizeof(size_t) ? sizeof(void *) : sizeof(size_t)) )
        {
            throw std::exception("nFixLen < max(sizeof(void *), sizeof(size_t))");
        }

        //必须对齐,不然有可能出现内存访问异常
        m_nFixLen = (nFixLen + sizeof(int) - 1) & ~(sizeof(int) - 1);
        m_nExpectObjectCnt = nExpectObjectCnt;

        if (m_nExpectObjectCnt < 1024)
        {
            m_nExpectObjectCnt = 1024;
        }

        m_allocSpaceLink = m_freeSpaceLink = NULL;
        allocFromSystem();
    }

    ~CHchFixLenMemPool()
    {
        //遍历链表节点
        while (m_allocSpaceLink)
        {
            SHchFixLenMemPoolLinkNode *pNext = m_allocSpaceLink->m_next;
            delete [](void *)m_allocSpaceLink;
            m_allocSpaceLink = pNext;
        }
    }

    void *alloc()
    {
        //如果存在已回收的空间,则直接分配出去
        if (m_freeSpaceLink != NULL)
        {
            void *p = m_freeSpaceLink;
            m_freeSpaceLink = m_freeSpaceLink->m_next;
            return p;
        }

        //不然需要从m_allocSpaceLink里面切一块出来
        char *pRetSpace = m_currAllocSpace; //pRetSpace指向待返回的空间

        //如果上次new出来的内存还没分配完,则直接分配即可
        if (m_nLeft != 0)
        {
            --m_nLeft;
            m_currAllocSpace += m_nFixLen;
            return pRetSpace;
        }

        //当前new出来的空间空间全部分配完 则需要重新向系统申请内存
        allocFromSystem();

        //这段跟前面分配逻辑是一样的
        //考虑到cpu流水线预测,刻意这样重复写代码 
        pRetSpace = m_currAllocSpace;
        --m_nLeft;
        m_currAllocSpace += m_nFixLen;
        return pRetSpace;
    }

    void free(void *pSpace)
    {
        if (pSpace == NULL)
        {
            return;
        }

        //如果回收空间链表为空,则直接修改m_allocSpaceLinke即可
        SHchFixLenMemPoolLinkNode *p = (SHchFixLenMemPoolLinkNode *)pSpace;
        if (m_allocSpaceLink == NULL)
        {
            m_allocSpaceLink = p;
            m_allocSpaceLink->m_next = NULL;
            return;
        }

        //否则将当前空间插到链表头
        p->m_next = m_freeSpaceLink;
        m_freeSpaceLink = p;
        return;
    }

private:
    //从系统分配内存
    void allocFromSystem()
    {
        SHchFixLenMemPoolLinkNode *pNextLink = m_allocSpaceLink;
        //new失败会抛异常,不需要考虑
        m_allocSpaceLink = (SHchFixLenMemPoolLinkNode *)
            new char[sizeof(SHchFixLenMemPoolLinkNode) + m_nFixLen * m_nExpectObjectCnt];

        m_allocSpaceLink->m_next = pNextLink;
        m_nLeft = m_nExpectObjectCnt;
        m_currAllocSpace = ((char *)m_allocSpaceLink) + sizeof(SHchFixLenMemPoolLinkNode);
    }

    size_t m_nFixLen; //内存池定长
    size_t m_nLeft; //已申请未分配个数
    size_t m_nExpectObjectCnt; //每次申请多少个定长的空间

    //当前可分配的空间指针
    char *m_currAllocSpace;

    //回收空间链表 m_next指向下一个已回收空间
    SHchFixLenMemPoolLinkNode *m_freeSpaceLink;

    //已向系统申请的空间链表
    //链表中每个节点均指向new返回的指针
    //m_next指向下一个已向申请空间
    SHchFixLenMemPoolLinkNode *m_allocSpaceLink;
};

template<typename  T>
T *newClassFromPool(CHchFixLenMemPool& objPool, const T& other)
{
    T *pState = (T *)objPool.alloc();
    new(pState) T(other);
    return pState;
}

template<typename  T, typename  T1>
T *newClassFromPool(CHchFixLenMemPool& objPool, const T1& param)
{
    T *pState = (T *)objPool.alloc();
    new(pState) T(param);
    return pState;
}

template<typename  T>
T *newClassFromPool(CHchFixLenMemPool& objPool)
{
    T *pState = (T *)objPool.alloc();
    new(pState) T();
    return pState;
}

template<class T>
void deleteClassFromPool(CHchFixLenMemPool& objPool, T * pState)
{
    pState->~T();
    objPool.free(pState);
}

#ifdef __POP_NEW_FLAG__
#pragma pop_macro("new")
#endif

#endif
// testObjPool.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "CHchFixLenMemPool.h"
#ifdef WIN32
#include <Windows.h>
#endif
#include <stdio.h>

class CSimpleBuffer
{
public:
    CSimpleBuffer(size_t size = 32)
    {
        m_memSize = size;
        m_pMem = new char[m_memSize];
    }

    CSimpleBuffer(const CSimpleBuffer& other)
    {
        m_memSize = other.m_memSize;
        m_pMem = new char[m_memSize];
        memcpy(m_pMem, other.m_pMem, m_memSize);
    }

    char *getMem()
    {
        return m_pMem;
    }

    size_t getMemSize()
    {
        return m_memSize;
    }

    ~CSimpleBuffer()
    {
        delete []m_pMem;
    }
private:
    size_t m_memSize;
    char *m_pMem;
};


#ifdef WIN32

class CMyTiming
{
public:
    CMyTiming()
    {
        m_startFlag = false;
    }

    bool startTiming() //开始计时
    {
        if (m_startFlag)
        {
            return false;
        }
        m_startFlag = true;

        QueryPerformanceFrequency(&m_litmp); /*获得时钟频率*/ 
        m_dff = m_litmp.QuadPart;

        QueryPerformanceCounter(&m_litmp); /*获得初始值*/ 
        m_qtBeg = m_litmp.QuadPart;

        return true;
    }

    double getTiming() //获得当前消耗时间
    {
        if (!m_startFlag)
        {
            return -1;
        }


        QueryPerformanceCounter(&m_litmp); /*获得终止值*/ 
        m_qtEnd = m_litmp.QuadPart;
        m_dfm = (m_qtEnd - m_qtBeg);
        m_dft = ((double) m_dfm) / m_dff; /*获得对应的时间值*/
        return m_dft;
    }

    void endTiming() //停止计时
    {
        m_startFlag = false;
    }
private:
    bool m_startFlag;
    LARGE_INTEGER m_litmp;
    LONGLONG m_qtBeg, m_qtEnd, m_dff, m_dfm;
    double m_dft;
};
#endif


int _tmain(int argc, _TCHAR* argv[])
{
    const int nTimes = 209600;
    const int n = 8000;
    CSimpleBuffer *pArray[nTimes];
    CMyTiming runTimeInfo;

    printf("total new times %d\n", nTimes * n);
    runTimeInfo.startTiming();

    for (int i = 0; i < n * nTimes; i++)
    {
        int nPos =  i / n;
        pArray[nPos] = new CSimpleBuffer(64);
        pArray[nPos]->getMem()[0] = '\0';
        if (i % n != (n - 1)) delete pArray[nPos];
    }

    for (int i = 0; i < nTimes; i++)
    {
        int nPos =  i / n;
        strcpy(pArray[nPos]->getMem(), "hell8ffff                                  fffff");
        pArray[nPos]->getMem()[i % 64] = '2';
        pArray[nPos]->getMem()[i % 32] =  i;
        if (i % n == (n - 1)) delete pArray[nPos];
    }

    printf("sec1 %.4f\n", runTimeInfo.getTiming());

    runTimeInfo.endTiming();
    runTimeInfo.startTiming();
    CHchFixLenMemPool objPool(sizeof(CSimpleBuffer), 8096);

    for (int i = 0; i < n * nTimes; i++)
    {
        int nPos =  i / n;
        pArray[nPos] = newClassFromPool<CSimpleBuffer, size_t>(objPool, 64);
        pArray[nPos]->getMem()[0] = '\0';
        if (i % n != (n - 1)) deleteClassFromPool(objPool, pArray[nPos]);
    }

    for (int i = 0; i < nTimes; i++)
    {
        int nPos =  i / n;
        strcpy(pArray[nPos]->getMem(), "hell8ffff                                  fffff");
        pArray[nPos]->getMem()[i % 64] = '2';
        pArray[nPos]->getMem()[i % 32] =  i;
        if (i % n == (n - 1)) deleteClassFromPool(objPool, pArray[nPos]);
    }

    printf("sec2 %.4f\n", runTimeInfo.getTiming());
    
    return 0;
}
View Code

 

posted @ 2017-06-11 22:15  皇家救星  阅读(684)  评论(1编辑  收藏  举报