使用C/C++实现内存池技术

本文介绍使用C/C++实现内存池技术的方法,通过创建和管理缓冲区对象提高程序效率,减少内存碎片。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用C/C++实现内存池技术

内存管理技术是开发多媒体应用和服务的很重要的知识。DMSP应用中会有频繁的缓冲区的创建和释放操作,这些操作会降低程序的运行效率和运行时间。本节在讲解内存池技术的同时,讲解对象的创建和使用方法。

内存池技术主要的思想是:被创建的缓冲区,在使用完后,并不立即释放,而是存放在一个空闲队列池中;当程序需要新的缓冲区时,首先从内存池中获取可用的缓冲区;在内存池中没有可用的缓冲区时,才去创建新的。通过这种内存池方法,可以减少频繁的缓冲区的创建和释放操作,减少内存碎片的发生,从而较有效的管理缓冲区。

内存池技术中,每一块内存被当作一个内存对象(IXBufferItem),这些对象可以管理自已的生成周期;同时,结合内存管理器对象(IXBufferManager)的管理功能,在内存对象需要被释放时,调用内存管理对象的相应接口(Reuse)通知管理对象自已需要被释放,讯问是否被再次利用,并根据返回的情况决定是释放自已,还是其他操作。

 

内存对象及其内存池管理对象被定义在下表中的源代码文件中。x_buffer_manager.h定义了内存对象和内存池管理对象,还定义了相关的操作函数组。

源文件x_buffer_manager.h


// x_buffer_manager.h: 缓冲区结点及其管理定义;
#ifndef _x_buffer_manager_h_
#define _x_buffer_manager_h_
 
#include "../include/x_nb_baseobject.h"
 
//缓冲区对象;
class IXBufferItem : public ISelfBaseObject
{
public:
virtual    unsigned long __stdcall GetLength(unsigned long* pdwLength) = 0;
virtual    unsigned long __stdcall SetLength(unsigned long dwLength) = 0;
virtual    unsigned long __stdcall GetMaxLength(unsigned long* pdwLength) = 0;  
virtual    unsigned long __stdcall GetBuffer(unsigned char** ppdwBuffer) = 0;
virtual    unsigned long __stdcall GetBufferAndLength(unsigned char** ppdwBuffer,  unsigned long *pdwLength) = 0;
};
 
//缓冲区管理对象;
class IXBufferManage : public ISelfBaseObject
{
public:
virtual    unsigned long __stdcall Init(long inMaxCount) = 0;
virtual    unsigned long __stdcall Uninit(void) = 0;
 
virtual    unsigned long __stdcall GetEmptySample(unsigned long inRequiredSize, IXBufferItem** outBuffer) = 0;
virtual    unsigned long __stdcall Reuse(IXBufferItem* inSample) = 0;
 
};
 
#ifdef __cplusplus
extern "C" {
#endif
 
// CreateBufferItem: 创建缓冲区对象;
HRESULT __stdcall CreateBufferItem(LPVOID* lppvObj);
 
// CreateBufferManager: 创建缓冲区管理对象;
HRESULT __stdcall CreateBufferManager(LPVOID* lppvObj);
 
#ifdef __cplusplus
}
#endif
 
#endif    //(!_x_buffer_manager_h_)

 

IXBufferItemIXBufferManage都从ISelfBaseObject派生而来。还应注意上例源代码中,使用虚函数和虚基类定义对象及其接口的方法。在实现这两个对象时,需要创建他们的实例;这两个函数的实例分别定义在下列源代码文件中。

源代码文件:buffmgr.h

// buffmgr: 缓冲区对象及其管理接口组;
#ifndef _buffmgr_h_
#define _buffmgr_h_
 
#include "../include/x_buffer_manager.h"
……
#endif    //(!_buffmgr_h_)

 

源代码文件:buffer_item.h

// buffer_item: 缓冲区对象接口组;
#ifndef _buffer_item_h_
#define _buffer_item_h_
 
#include "buffmgr.h"
class CXBufferManage;
 
// CXBufferItem: 缓冲区对象接口组;
class CXBufferItem : public IXBufferItem
{
public: //ISelfBaseObject接口;
virtual    HRESULT      __stdcall QueryInterface(REFIID iid,
LPVOID *lppvObject);
virtual    ULONG  __stdcall AddRef(VOID);
virtual    ULONG  __stdcall Release(VOID);
virtual    DWORD __stdcall GetVersion(LPDWORD pdwHigh);
 
public: //IXBufferItem接口;
virtual    unsigned long __stdcall GetLength(unsigned long* pdwLength);
virtual    unsigned long __stdcall SetLength(unsigned long dwLength);
virtual    unsigned long __stdcall GetMaxLength(unsigned long* pdwLength);  
virtual    unsigned long __stdcall GetBuffer(unsigned char** ppdwBuffer);
virtual    unsigned long __stdcall GetBufferAndLength(unsigned char** ppdwBuffer, unsigned long *pdwLength);
 
public:
CXBufferItem(unsigned long inSize, CXBufferManage* pSmpMgr);
CXBufferItem();
~CXBufferItem();
 
public:
unsigned long       SetBufferManage(CXBufferManage* pSmpMgr);
unsigned long       VerifyBufferSize(unsigned long inRequiredSize);
 
public:
CXBufferItem*    m_pNext;       //后一个对象;
 
private:
long                 m_cRef;         //引用的计数;
unsigned char*     m_pBuffer;     //缓冲区地址;
unsigned long       m_dwBufSize;       //缓冲区长度;
unsigned long       m_dwDataSize;      //数据的长度;
 
CXBufferManage*       m_pSmpAdmin;     //缓冲的管理;
};
 
#endif    //(!_buffer_item_h_)


源代码文件:buffer_manage.h


// buffer_manage.h: 缓冲区对象管理接口组;
#ifndef _buffer_manage_h_
#define _buffer_manage_h_
 
#include "buffmgr.h"
class CXBufferItem;
 
// CXBufferManage: 缓冲区对象管理接口组;
class CXBufferManage : public IXBufferManage
{
public: //ISelfBaseObject接口;
virtual    HRESULT      __stdcall QueryInterface(REFIID iid,
LPVOID *lppvObject);
virtual    ULONG  __stdcall AddRef(VOID);
virtual    ULONG  __stdcall Release(VOID);
virtual    DWORD __stdcall GetVersion(LPDWORD pdwHigh);
 
public: //IXBufferManage接口;
virtual    unsigned long __stdcall Init(long inMaxCount);
virtual    unsigned long __stdcall Uninit(void);
 
virtual    unsigned long __stdcall GetEmptySample(unsigned long inRequiredSize, IXBufferItem** outBuffer);
virtual    unsigned long __stdcall Reuse(IXBufferItem* inSample);
 
public:
CXBufferManage();
~CXBufferManage();
 
private:
long                        m_cRef;                //引用计数;
CXBufferItem*           m_pIdleHead;         //空闲队列头;
CXBufferItem*           m_pIdleTail;          //空闲队列尾;
long                        m_nMaxCount;             //最大个数;
long                        m_nCurCount;              //当前个数;
……
};
……
#endif //(!_buffer_manage_h_)

 

CXBufferItem实现了IXBufferItem的所有的虚拟函数接口,同时在其对象内部保存了一个缓冲区对象。其中m_pBuffer指向缓冲区的首地址,m_dwBufSize是缓冲区的长度,m_dwDataSize是缓冲区中的数据长度;同时,m_pSmpAdmin是内存对象的管理器,当内存对象需要释放时,首先检查该对象是否存在,如果存在,则调用该对象的Reuse接口通知它回收回已;如果管理器对象不存在或者不回收自己,则CXBufferItem释放直接释放自己,这通过它的接口Release来实现。该类还有一个成员是m_pNext,它被内存池管理器对象使用。类CXBufferItem的其它对象主要是便于缓冲区的管理。具体的实现见下例中的源代码。

源代码文件:buffer_item.cpp


// buffer_item: 缓冲区结点函数组;

#include "buffer_item.h"

#include "buffer_manage.h"

 

// ISelfBaseObject接口函数组;

HRESULT    __stdcall CXBufferItem::QueryInterface(REFIID iid,

LPVOID *lppvObject)

{

     *lppvObject = reinterpret_cast<ISelfBaseObject*>(this);

     this->AddRef();

     return S_OK;

}

 

ULONG __stdcall CXBufferItem::AddRef(VOID)

{

     return ::InterlockedIncrement(&m_cRef);

}

 

ULONG __stdcall CXBufferItem::Release(VOID)

{

     if(0 == ::InterlockedDecrement(&m_cRef))

     {

            if(m_pSmpAdmin != NULL)

            {

                   //调用管理器回收缓冲区;

                   m_pSmpAdmin->Reuse(this);

            }

            else  {

                   //释放缓冲区;

                   delete this;

            }

            return      0;

     }

     return      (ULONG)m_cRef;

}

 

DWORD      __stdcall CXBufferItem::GetVersion(LPDWORD pdwHigh)

{

     if(pdwHigh != NULL)

     {

            *pdwHigh = 0x00000001;

     }

     return      0x00010000;

}

 

//构造函数(传入尺寸和管理对象);

CXBufferItem::CXBufferItem(unsigned long inSize,

CXBufferManage* pSmpMgr)

{

     m_cRef = 0;

 

     m_dwBufSize  = 0;

     m_dwDataSize = 0;

     m_pBuffer  = new unsigned char[inSize];

     if(m_pBuffer != NULL)

     {

            m_dwBufSize  = inSize;

            m_dwDataSize = inSize;

     }

     m_pSmpAdmin = pSmpMgr;

     if(m_pSmpAdmin != NULL)

     {

            m_pSmpAdmin->AddRef();

     }

     m_pNext = NULL;

}

 

//缺省构造函数;

CXBufferItem::CXBufferItem()

{

     m_pBuffer = NULL;

     m_dwBufSize = 0;

     m_dwDataSize = 0;

     m_pSmpAdmin = NULL;

     m_pNext = NULL;

}

 

//析构函数;

CXBufferItem::~CXBufferItem()

{

     //释放缓冲区;

     if(m_pBuffer != NULL)

     {

            delete[] m_pBuffer;

     }

     m_pBuffer = NULL;

     //释放对管理对象的引用;

     if(m_pSmpAdmin != NULL)

     {

            m_pSmpAdmin->Release();

     }

     m_pSmpAdmin = NULL;

}

 

//设置管理对象;

unsigned long CXBufferItem::SetBufferManage(CXBufferManage* pSmpMgr)

{

     //释放原有的管理对象(如果有);

     if(m_pSmpAdmin != NULL)

     {

            m_pSmpAdmin->Release();

     }

     //保存管理对象(增加引用计数);

     m_pSmpAdmin = pSmpMgr;

     if(m_pSmpAdmin != NULL)

     {

            m_pSmpAdmin->AddRef();

     }

     return      0;

}

 

//调用缓冲区的大小(在原缓冲区较小时);

unsigned long CXBufferItem::VerifyBufferSize(unsigned long inRequiredSize)

{   

     unsigned long  hr = 0;

 

     if(inRequiredSize > m_dwBufSize)

     {

            if(m_pBuffer != NULL)

            {

                   delete[] m_pBuffer;

                   m_pBuffer = NULL;

            }

            m_pBuffer = new unsigned char[inRequiredSize];

            if(m_pBuffer != NULL)

            {

                   m_dwBufSize  = inRequiredSize;

                   m_dwDataSize = inRequiredSize;

                   hr = 0;

            }

            else  {

                   m_dwBufSize  = NULL;

                   m_dwDataSize = NULL;

                   hr = -1;

            }

     }

return      hr;

}

 

//获取缓冲区中数据的长度;

unsigned long __stdcall CXBufferItem::GetLength(unsigned long *pdwLength)

{

     *pdwLength = m_dwDataSize;

     return 0;

}

 

//设置缓冲区中数据的长度;

unsigned long  __stdcall CXBufferItem::SetLength(unsigned long dwLength)

{

     m_dwDataSize = dwLength;

     return 0;

}

 

//获取缓冲区的总长度;

unsigned long  __stdcall CXBufferItem::GetMaxLength(unsigned long *pdwLength)

{

     *pdwLength = m_dwBufSize;

     return 0;

}

 

//获取缓冲区的地址;

unsigned long __stdcall CXBufferItem::GetBuffer(unsigned char **ppdwBuffer)

{

     *ppdwBuffer = m_pBuffer;

     return 0;

}

 

//获取缓冲区的地址和数据的长度;

unsigned long  __stdcall CXBufferItem::GetBufferAndLength(unsigned char **ppdwBuffer, unsigned long *pdwLength)

{

     *ppdwBuffer = m_pBuffer;

     *pdwLength  = m_dwDataSize;

     return 0;

}

 

CXBufferManage实现了IXBufferManage的所有的虚拟函数接口,同时在其对象内部设置一个单向链表用于存储空闲内存对象。m_pIdleHead指向该表的表头;m_pIdleTail指向该表的表尾;m_nMaxCount设置最大可以保存的空闲对象的个数;m_nCurCount保存当前空闲对象的个数。类CXBufferManage的接口Init用于设置最大可以保存的空闲对象的个数;在该类CXBufferManage的实例在释放时,会调用Uninit释放所有的被保存的空闲内存对象。

调用者调用该类CXBufferManageGetEmptySample接口获取内存对象;GetEmptySample接口首先从空闲队列中获取内存对象;如果没有可用的空闲对象,则创建新的内存对象;当内存对象IXBufferItem不再使用时,调用CXBufferManageReuse接口,该接口首先检查空闲内存对象是否达到最大值,如果没有,则把传入的对象加入到空闲队列中;如果达到最大值,则不加入到队列中。类CXBufferManage的实现见下例中的源代码。

源代码文件:buffer_manage.cpp


……

// buffer_manage.cpp: 缓冲区对象管理接口组;

#include "buffer_item.h"

#include "buffer_manage.h"

 

// ISelfBaseObject接口函数组;

HRESULT    __stdcall CXBufferManage::QueryInterface(REFIID iid,

LPVOID *lppvObject)

{

     *lppvObject = reinterpret_cast<ISelfBaseObject*>(this);

     this->AddRef();

     return S_OK;

}

 

ULONG __stdcall CXBufferManage::AddRef(VOID)

{

     return ::InterlockedIncrement(&m_cRef);

}

 

ULONG __stdcall CXBufferManage::Release(VOID)

{

     if(0 == ::InterlockedDecrement(&m_cRef))

     {

            delete this;

            return      0;

     }

     return      (ULONG)m_cRef;

}

 

DWORD      __stdcall CXBufferManage::GetVersion(LPDWORD pdwHigh)

{

     if(pdwHigh != NULL)

     {

            *pdwHigh = 0x00000001;

     }

     return      0x00010000;

}

 

//构造函数;

CXBufferManage::CXBufferManage()

{

     m_cRef = 1;

     m_nMaxCount = 10;

     m_nCurCount = 0;

     m_pIdleHead = NULL;

     m_pIdleTail = NULL;

}

 

//析构函数(释放所有管理的对象);

CXBufferManage::~CXBufferManage()

{

     Uninit();

}

 

//初始化管理器(指明最大个数);

unsigned long __stdcall CXBufferManage::Init(long inMaxCount)

{

     if(inMaxCount > m_nMaxCount)

     {

            m_nMaxCount = inMaxCount;

     }

     return      1;

}

 

//释放管理器的信息;

unsigned long __stdcall CXBufferManage::Uninit(void)

{

     CXBufferItem*      pSample = NULL;

     CXBufferItem*      pTmp = NULL;

 

     //释放管理的所有缓冲区对象;

     pSample = m_pIdleHead;

     while(pSample)

     {

            pTmp = pSample->m_pNext;

            pSample->SetBufferManage(NULL);

            pSample->Release();

            pSample = pTmp;

     }

     m_pIdleHead = NULL;

     m_pIdleTail = NULL;

     m_nCurCount = 0;

 

     return      1;

}

 

//创建或获取缓冲区对象;

unsigned long  __stdcall CXBufferManage::GetEmptySample(unsigned long inRequiredSize, IXBufferItem** outBuffer)

{

     CXBufferItem*      pSample = NULL;

 

     //检查参数;

     if(!outBuffer) return 0;

     *outBuffer = NULL;

 

     //创建新的缓冲区对象(如果没有);

     if(m_pIdleHead == NULL)

     {

            //创建新对象;

            pSample = new CXBufferItem(inRequiredSize, this);

            if(pSample == NULL)

            {

                   return 0;

            }

            pSample->VerifyBufferSize(inRequiredSize);

     }

     else  {

            pSample = m_pIdleHead;

            pSample->AddRef();

            //调整表;

            m_pIdleHead = m_pIdleHead->m_pNext;

            if(m_pIdleHead == NULL)

            {

                   m_pIdleTail = NULL;

            }

            m_nCurCount --;

     }

 

     //调整结点信息;

     pSample->VerifyBufferSize(inRequiredSize);

     *outBuffer = (IXBufferItem*)pSample;

     return      1;

}

 

//回收缓冲区对象(直接加入到空闲表中);

unsigned long  __stdcall CXBufferManage::Reuse(IXBufferItem* inSample)

{

     CXBufferItem*      pSam = NULL;

 

     //检查参数;

     if(!inSample) return 0;

     pSam = (CXBufferItem*)inSample;

     pSam->m_pNext = NULL;

 

     //结点尝试加入到表的尾部;

     if(m_nCurCount < m_nMaxCount)

     {

            if(!m_pIdleTail)

            {

                   m_pIdleHead = pSam;

                   m_pIdleTail = pSam;

            }

            else  {

                   m_pIdleTail->m_pNext = pSam;

                   m_pIdleTail = pSam;

            }

            m_nCurCount ++;

            return 1;

     }

     return      0;

}

 

对象IXBufferItemIXBufferManage可以保存在DLL动态库文件中,本例通过输出函数接口CreateBufferItemCreateBufferManager来创建这两个对象;同时,通过相应的DEF文件来设置输出的接口。实现细节见下表中的源代码。

源代码文件:buffmgr.cpp


// buffmgr: 缓冲区对象及其管理接口组;

#include "buffmgr.h"

#include "buffer_item.h"

#include "buffer_manage.h"

……

//全局变量;

HINSTANCE       ghInstance = NULL;      //库的实例句柄;

 

//动态库输出主函数;

BOOL APIENTRY DllMain( HANDLE hModule,

DWORD  ul_reason_for_call, LPVOID lpReserved)

{

     switch (ul_reason_for_call)

     {

            case DLL_PROCESS_ATTACH:

            {

                   ghInstance = (HINSTANCE)hModule;

                   DisableThreadLibraryCalls(ghInstance);

                   break;

            }

            case DLL_PROCESS_DETACH:

            {

                   break;

            }

     }

     return      TRUE;

}

 

// CreateBufferItem: 创建缓冲区对象;

HRESULT __stdcall CreateBufferItem(LPVOID* lppvObj)

{

     CXBufferItem*      lpirc = NULL;

     HRESULT             hr = S_OK;

 

     //创建一个对象;

     lpirc = new CXBufferItem;

     if(lpirc == NULL)

     {

            return E_OUTOFMEMORY;

     }

 

     //查寻对象以获取接口;

     hr = lpirc->QueryInterface(IID_ISelfBaseObject, lppvObj);

     lpirc->Release();

 

     //返回处理结果;

     return hr;

}

 

// CreateBufferManager: 创建缓冲区管理对象;

HRESULT __stdcall CreateBufferManager(LPVOID* lppvObj)

{

     CXBufferManage*  lpirc = NULL;

     HRESULT             hr = S_OK;

 

     //创建一个对象;

     lpirc = new CXBufferManage;

     if(lpirc == NULL)

     {

            return E_OUTOFMEMORY;

     }

 

     //查寻对象以获取接口;

     hr = lpirc->QueryInterface(IID_ISelfBaseObject, lppvObj);

     lpirc->Release();

 

     //返回处理结果;

     return hr;

}

……

 

源代码文件:buffmgr.def


……

EXPORTS

CreateBufferItem  @1

CreateBufferManager   @2

……

 

对象IXBufferItemIXBufferManage保存在DLL动态库文件(buffmgr.dll)中,其关联文件存放在buffmgr.lib文件中。使用该对象库时,可以使用显示调用方法,也可以使用隐式调用方法。示例文件buffer_reuse.cpp给出了一种隐式调用的方法。细节见相应的源代码文件。

源代码文件:buffer_resuse.cpp


// buffer_reuse: 重用缓冲区测试示例;

#include <stdio.h>

#include "../../include/x_buffer_manager.h"

#pragma comment(lib, "../../lib/buffmgr.lib")

 

int main(int argc, char* argv[])

{

     IXBufferManage*   pXBM = NULL;

     IXBufferItem*              pXBItem = NULL;

     unsigned long         nBufferSize = 64*1024;

     long                     num = 0;

 

     //创建缓冲管理器;

     CreateBufferManager((void**)&pXBM);

     if(pXBM == NULL)

     {

            printf("Error buffer manager!\r\n");

            return -1;

     }

 

     //初始化缓冲池;

     pXBM->Init(100);

 

     //循环获取和释放缓冲区;

     for(num=0; num<20; num++)

     {

            pXBM->GetEmptySample(nBufferSize, &pXBItem);

            if(pXBItem != NULL)

            {

                   //回收缓冲区;

                   pXBItem->Release();

                   pXBItem = NULL;

            }

     }

 

     //释放缓冲池;

     pXBM->Uninit();

 

     //删除缓冲管理器;

     pXBM->Release();

     pXBM = NULL;

     return      0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值