用内存池管理c++对象

原创 2017年07月29日 13:55:49

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

   

   

版权声明:本文为博主原创文章,未经博主允许不得转载。

对象内存池技术

 在这里,还是先介绍下我们这边对象内存池技术的基本概念和设计过程: 所谓的对象内存池技术设计过程如下:首先为某种对象预先生成若干个空闲对象,并且使用对象管理类进行管理。应用程序在需要使用此对象时,即向...
  • blade2001
  • blade2001
  • 2006年09月29日 14:00
  • 1009

一个C++的内存池和内存管理的实现(一)

用C++编写高效稳定的软件,有效的内存管理通常是绕不开的一个题目,尤其是对于复杂庞大的商业软件。...
  • qiyao_2000
  • qiyao_2000
  • 2015年04月17日 18:11
  • 1058

C++实现多线程全局内存池(性能优化)

#include #include #include #include #include #include #include #include #include #include ...
  • freeangeles
  • freeangeles
  • 2016年06月08日 20:48
  • 1628

C/C++内存管理之内存池

C++内存管理一直是我比较困惑的问题。俗话说初生牛犊不怕虎,做点啥都new一个,然后delete一个。根本不知道底层会有怎么样的运行机制,慢慢地学习才知道以前学习中有一些东西是不可能在工业中应用的。所...
  • bateerBATEER
  • bateerBATEER
  • 2017年03月28日 21:38
  • 314

C++内存池(memory pool)管理

程序员在使用C++中的动态内存分配器时,new/delete, malloc/free等操作时,可能会出现以下问题: Memory Leak:new一块空间,但中间抛出错误,最后没有释放成功,导致...
  • yyf_it
  • yyf_it
  • 2016年08月28日 10:23
  • 581

C++ 实现高性能内存池

一、概述 在 C/C++ 中,内存管理是一个非常棘手的问题,我们在编写一个程序的时候几乎不可避免的要遇到内存的分配逻辑,这时候随之而来的有这样一些问题:是否有足够的内存可供分配? 分配失败了怎么办?...
  • xjtuse2014
  • xjtuse2014
  • 2016年08月24日 16:56
  • 3588

c++内存池的实现(可以new复杂对象)

#ifndef MEMORYPOOL_HPP define MEMORYPOOL_HPP/* 使用说明: 1>.如果是qt项目请打开#...
  • Garfiel_C
  • Garfiel_C
  • 2015年06月23日 22:13
  • 1089

【源码剖析】MemoryPool —— 简单高效的内存池 allocator 实现

内存池简单说,是为了减少频繁使用 malloc/free new/delete 等系统调用而造成的性能损耗而设计的。当我们的程序需要频繁地申请和释放内存时,频繁地使用内存管理的系统调用可能会造成性能的...
  • jcjc918
  • jcjc918
  • 2015年04月24日 16:48
  • 6351

c++对象池内存池实现

以前自己写过一个内存池,采取FreeList计数,总感觉那个性能无与伦比。 但上次看一个人测试基于boost::object_pool,和CRT的new/delete的速度比较。 在100...
  • 979797
  • 979797
  • 2013年08月23日 10:09
  • 1175

【Unity编程】Unity3D-使用对象池高效管理内存

本节通过一个简单的射击子弹的示例来介绍一个比较通用的Unity对象池的写法...
  • AndrewFan
  • AndrewFan
  • 2017年02月21日 08:01
  • 3597
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:用内存池管理c++对象
举报原因:
原因补充:

(最多只允许输入30个字)