用内存池管理c++对象

    当一个系统中 ,有一些对象需要频繁的申请和释放时,为了提高性能我们通常用内存池来管理这部分对象,这里给一个内存池的实现,我们用双向链表和数组实现内存池来管理c++对象。

     内存池类

     

//
//  mempool.h
//  Created by DGuco on 17/7/29.
//  Copyright © 2017年 DGuco. All rights reserved.
//  结合数组和双向链表实现对象内存池(注:使用该内存的类必须有无参的构造函数)
//

#ifndef SERVER_MEMPOOL_H
#define SERVER_MEMPOOL_H

#include 
  
  
   
   
template
   
   
    
    
class CMemoryPool
{
public:
    CMemoryPool(void) :	m_pElementsSetList(NULL),m_pUnusedElementsList(NULL)
    {
        
    }
    ~CMemoryPool(void)
    {
        if (GetPoolSize() > 0 || IsCreated()){
            //注意这里一般手动调用Destroy,在析构函数中调用是为了防止我们忘记手动调用`
            Destroy();
        }
    }
    
    //简直拷贝和赋值
    CMemoryPool(const CMemoryPool& other) = delete ;
    CMemoryPool&operator=(CMemoryPool& other) = delete;
private:
    //节点数据结构
    struct TagElement
    {
        Type		Element;
        TagElement*	pNext;
        TagElement*	pBefore;
    };
    
    //对象数组,注意这里的next的用途,当内存池的容量不够使,会另外开辟同等大小的空间来存储对象,
    //新数组的next会指向旧的数组,其实是一个链表,每个节点是一个数组
    struct TagElementsSet
    {
        //对象数组
        TagElement*		aElementsSet;
        TagElementsSet*	pNext;
    };
    
    //对象池数组
    TagElementsSet* m_pElementsSetList;
    //使用数量
    int			m_nNumOfAlloc;
    //当前可用的节点
    TagElement*	m_pUnusedElementsList;
    //一个数组的最大对象数量也是内存池的初始大小
    int			m_nNumOfElements;
    //数组数量
    int			m_nNumOfElementsSet;
    
public:
    //开辟指定数量的内存池
    bool	Create( uint nNumOfElements )
    {
        m_nNumOfElements	= nNumOfElements;
        m_nNumOfElementsSet	= 1;
        
        m_pElementsSetList					= new TagElementsSet;
        m_pElementsSetList->pNext			= NULL;
        //开辟数组
        m_pElementsSetList->aElementsSet	= new TagElement[m_nNumOfElements];
    
        //初始化链表结构
        for( int i = 0; i < m_nNumOfElements; i++ )
        {
            if( i > 0 )
            {
                m_pElementsSetList->aElementsSet[i].pBefore	= &m_pElementsSetList->aElementsSet[i-1];
                m_pElementsSetList->aElementsSet[i-1].pNext	= &m_pElementsSetList->aElementsSet[i];
            }
        }
        m_pElementsSetList->aElementsSet[0].pBefore					= NULL;
        m_pElementsSetList->aElementsSet[m_nNumOfElements-1].pNext	= NULL;
        
        //当前可用的节点信息
        m_pUnusedElementsList	= m_pElementsSetList->aElementsSet;
        m_nNumOfAlloc			= 0;
        return true;
    }
    
    //回收内存池
    void Destroy()
    {
        while( m_pElementsSetList )
        {
            if( m_pElementsSetList->aElementsSet )
            {
                delete[] m_pElementsSetList->aElementsSet;
                m_pElementsSetList->aElementsSet = NULL;
            }
            TagElementsSet* pFirst = m_pElementsSetList;
            m_pElementsSetList = m_pElementsSetList->pNext;
            
            delete pFirst;
        }
        m_nNumOfAlloc = 0;
        m_nNumOfAlloc = 0;
        m_nNumOfElementsSet = 0;
    }
    
    Type* Alloc()
    {
        //如果当前的链表使用完,开辟新的一条同等大小的链表
        if( m_pUnusedElementsList == NULL )
        {
            TagElementsSet* pSet	= new TagElementsSet;
            //把next之乡旧的数组
            pSet->pNext				= m_pElementsSetList;
            pSet->aElementsSet		= new TagElement[m_nNumOfElements];
            
            //初始化链表信息
            for( int i = 0; i < m_nNumOfElements; i++ )
            {
                if( i > 0 )
                {
                    pSet->aElementsSet[i].pBefore	= &pSet->aElementsSet[i-1];
                    pSet->aElementsSet[i-1].pNext	= &pSet->aElementsSet[i];
                }
            }
            pSet->aElementsSet[0].pBefore					= NULL;
            pSet->aElementsSet[m_nNumOfElements-1].pNext	= NULL;
            
            //把当前可用节点指向新数组的第一个元素
            m_pUnusedElementsList	= pSet->aElementsSet;
        
            m_pElementsSetList = pSet;
            m_nNumOfElementsSet++;
        }
        
        TagElement* pTagElement;
        pTagElement = m_pUnusedElementsList;
        m_pUnusedElementsList = m_pUnusedElementsList->pNext;
        if( m_pUnusedElementsList )
        {
            m_pUnusedElementsList->pBefore = NULL;
            
        }
    
        m_nNumOfAlloc++;
        return &(pTagElement->Element);
    }
    
    //回收一个对象
    void Free( Type* pElement )
    {
        TagElement* pTagElement = (TagElement*)pElement;
        pTagElement->pNext					= m_pUnusedElementsList;
        pTagElement->pBefore				= NULL;
        if( m_pUnusedElementsList )
            m_pUnusedElementsList->pBefore	= pTagElement;
        m_pUnusedElementsList				= pTagElement;
        m_nNumOfAlloc--;
    }
    
    int GetAllocatedSize()
    {
        return m_nNumOfAlloc;
    }
    
    int	GetPoolSize()
    {
        return m_nNumOfElements * m_nNumOfElementsSet;
    }
    
    bool IsCreated()
    {
        return m_pElementsSetList != NULL;
    }
    
};// class CMemoryPool

#endif //SERVER_MEMPOOL_H

   
   
  
  

     内存池安全操作接口

    

//
//
//  Created by DGuco on 17/7/29.
//  Copyright © 2017年 DGuco. All rights reserved.
//  内存池安全操作接口,线程安全
//

#ifndef SERVER_MEMPOOLSAFTY_H
#define SERVER_MEMPOOLSAFTY_H

#include 
  
  
   
   
#include "mempool.h"

/* 注意:创建和回收整个内存池两个操作不是线程安全的,
 * 这里没有锁保护是因为因为这两个操作一般在主线程中,
 * 使用的时候才会出现多线程同时操作
 */
template
   
   
    
    
class CMemoryPoolSafty : public CMemoryPool
    
    
     
     
{
private:
    std::mutex	m_utex;
    
public:
    //创建sizeof(Type) * nNumOfElements大小的空间
    bool Create(uint nNumOfElements)
    {
        return CMemoryPool
     
     
      
      ::Create(nNumOfElements);
    }
    
    //释放内存池空间
    void Destroy()
    {
        CMemoryPool
      
      
        ::Destroy(); } //从内存池中获取一个对象空间 Type* Alloc() { std::lock_guard 
       
         guard(m_utex); Type* pType; pType = CMemoryPool 
        
          ::Alloc(); return pType; } //内存池回收一个对象空间 void Free( Type* pElement ) { std::lock_guard 
         
           guard(m_utex); CMemoryPool 
          
            ::Free(pElement); } }; #endif //SERVER_MEMPOOLSAFTY_H 
           
          
         
        
      
     
     
    
    
   
   
  
  

     使用例子:

     

//
//
//  Created by DGuco on 17/7/29.
//  Copyright © 2017年 DGuco. All rights reserved.
//  内存池安全操作接口,线程安全
//

#include 
  
  
   
   
#include 
   
   
    
    
#include 
    
    
     
     
#include "memsafety.h"

using namespace std;

class Demo
{
public:
    Demo()
    {
        name = "";
        age = 0;
    }
    
    void init(string _name,int _age)
    {
        name = _name;
        age = _age;
    }
    
    string GetName() {return name;}
    int GetAge()  {return age;}
private:
    string name;
    int age;
};

int main()
{
    CMemoryPool
     
     
      
       memPool;
    //初始化内存池大小
    memPool.Create(5);
    std::vector
      
      
        demoArray; for (int i = 0; i< 10;i++) { Demo *demo = memPool.Alloc(); demo->init(to_string(i), i); demoArray.push_back(demo); } for (int i = 0; i< 10;i++) { std::cout<< "name:" << demoArray[i]->GetName() << " age:" << demoArray[i]->GetAge() << std::endl; memPool.Free(demoArray[i]); } memPool.Destroy(); std::cout << "Hello word" << std::endl; } 
      
     
     
    
    
   
   
  
  

   

   

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值