`
aigo
  • 浏览: 2644627 次
  • 性别: Icon_minigender_1
  • 来自: 宜昌
社区版块
存档分类
最新评论

【转】C++内存池

阅读更多

boost.pool内存池基准测试:

http://tech.it168.com/a2011/0726/1223/000001223399_all.shtml

如果编写的是用户态的进程,已经没有使用内存池的必要了;如果类有自己的构造函数和析构函数,那么boost.pool反而会性能下降。

 

原文地址 http://www.cppblog.com/d3d/archive/2008/11/28/68097.aspx

SMemoryChunk.h

#ifndef __SMEMORYCHUNK_H__
#define __SMEMORYCHUNK_H__

typedef unsigned char TByte ;

struct SMemoryChunk
{
  TByte *Data;                //数据 
  std::size_t DataSize;        //该内存块的总大小
  std::size_t UsedSize;        //实际使用的大小
  bool IsAllocationChunk;    
  SMemoryChunk *Next;        //指向链表中下一个块的指针。
};

#endif

 

 

 

IMemoryBlock.h

#ifndef __IMEMORYBLOCK_H__
#define __IMEMORYBLOCK_H__

class IMemoryBlock
{
  public :
    virtual ~IMemoryBlock() {};

    virtual void *GetMemory(const std::size_t &sMemorySize) = 0;
    virtual void FreeMemory(void *ptrMemoryBlock, const std::size_t &sMemoryBlockSize) = 0; 

};

#endif

 

CMemoryPool.h

#ifndef __CMEMORYPOOL_H__
#define __CMEMORYPOOL_H__


#include "IMemoryBlock.h"
#include "SMemoryChunk.h"


static const std::size_t DEFAULT_MEMORY_POOL_SIZE        = 1000;//初始内存池的大小
static const std::size_t DEFAULT_MEMORY_CHUNK_SIZE       = 128;//Chunk的大小
static const std::size_t DEFAULT_MEMORY_SIZE_TO_ALLOCATE = DEFAULT_MEMORY_CHUNK_SIZE * 2;

class CMemoryPool : public IMemoryBlock
{
public:
    CMemoryPool(const std::size_t &sInitialMemoryPoolSize = DEFAULT_MEMORY_POOL_SIZE, 
                const std::size_t &sMemoryChunkSize = DEFAULT_MEMORY_CHUNK_SIZE,
                const std::size_t &sMinimalMemorySizeToAllocate = DEFAULT_MEMORY_SIZE_TO_ALLOCATE,
                bool bSetMemoryData = false
                );


    virtual ~CMemoryPool();

    //从内存池中申请内存
    virtual void* GetMemory(const std::size_t &sMemorySize);
    virtual void  FreeMemory(void *ptrMemoryBlock, const std::size_t &sMemoryBlockSize);
    
private:
    //申请内存OS
    bool AllocateMemory(const std::size_t &sMemorySize);
    void FreeAllAllocatedMemory();
    SMemoryChunk* FindChunkHoldingPointerTo(void *ptrMemoryBlock);
    void FreeChunks(SMemoryChunk *ptrChunk);
    //计算可以分多少块
    unsigned int CalculateNeededChunks(const std::size_t &sMemorySize);

    //计算内存池最合适的大小
    std::size_t CMemoryPool::CalculateBestMemoryBlockSize(const std::size_t &sRequestedMemoryBlockSize);
    
    //建立链表.每个结点Data指针指向内存池中的内存地址
    bool LinkChunksToData(SMemoryChunk* ptrNewChunks, unsigned int uiChunkCount, TByte* ptrNewMemBlock);
    
    //重新计算块(Chunk)的大小1024--896--768--640--512------------
    bool RecalcChunkMemorySize(SMemoryChunk* ptrChunk, unsigned int uiChunkCount);
    
    SMemoryChunk* SetChunkDefaults(SMemoryChunk *ptrChunk);
    

    //搜索链表找到一个能够持有被申请大小的内存块(Chunk).如果它返回NULL,那么在内存池中没有可用的内存
    SMemoryChunk* FindChunkSuitableToHoldMemory(const std::size_t &sMemorySize);

    std::size_t MaxValue(const std::size_t &sValueA, const std::size_t &sValueB) const;
    
    void SetMemoryChunkValues(SMemoryChunk *ptrChunk, const std::size_t &sMemBlockSize);

    SMemoryChunk* SkipChunks(SMemoryChunk *ptrStartChunk, unsigned int uiChunksToSkip);
    
    void DeallocateAllChunks();

private:

    SMemoryChunk *m_ptrFirstChunk;
    SMemoryChunk *m_ptrLastChunk;   
    SMemoryChunk *m_ptrCursorChunk;

    std::size_t m_sTotalMemoryPoolSize;  //内存池的总大小
    std::size_t m_sUsedMemoryPoolSize;   //以使用内存的大小
    std::size_t m_sFreeMemoryPoolSize;   //可用内存的大小

    std::size_t m_sMemoryChunkSize;     //块(Chunk)的大小
    unsigned int m_uiMemoryChunkCount;  //块(Chunk)的数量
    unsigned int m_uiObjectCount;

    bool m_bSetMemoryData ; 
    std::size_t m_sMinimalMemorySizeToAllocate;


};

#endif

 

 

CMemoryPool.cpp

#include "stdafx.h"
#include "CMemorypool.h"

#include <math.h>
#include <assert.h>


static const int FREEED_MEMORY_CONTENT        = 0xAA;//填充释放的内存 
static const int NEW_ALLOCATED_MEMORY_CONTENT = 0xFF;


CMemoryPool::CMemoryPool(const std::size_t &sInitialMemoryPoolSize,
                         const std::size_t &sMemoryChunkSize,
                         const std::size_t &sMinimalMemorySizeToAllocate,
                         bool bSetMemoryData)
{
    m_ptrFirstChunk  = NULL;
    m_ptrLastChunk   = NULL;
    m_ptrCursorChunk = NULL;

    m_sTotalMemoryPoolSize = 0;
    m_sUsedMemoryPoolSize  = 0;
    m_sFreeMemoryPoolSize  = 0;

    m_sMemoryChunkSize   = sMemoryChunkSize;
    m_uiMemoryChunkCount = 0;
    m_uiObjectCount      = 0;

    m_bSetMemoryData               = !bSetMemoryData;
    m_sMinimalMemorySizeToAllocate = sMinimalMemorySizeToAllocate;

    AllocateMemory(sInitialMemoryPoolSize);
}

CMemoryPool::~CMemoryPool()
{
    FreeAllAllocatedMemory();
    DeallocateAllChunks();

    assert((m_uiObjectCount == 0) && "警告:内存-泄露:你没有释放全部申请的内存");
}

void CMemoryPool::FreeAllAllocatedMemory()
{
    SMemoryChunk *ptrChunk = m_ptrFirstChunk;
    while(ptrChunk)
    {
        if(ptrChunk->IsAllocationChunk)
        {
            free(((void *) (ptrChunk->Data)));
        }
        ptrChunk = ptrChunk->Next;
    }
}

void CMemoryPool::DeallocateAllChunks()
{
    SMemoryChunk *ptrChunk = m_ptrFirstChunk;
    SMemoryChunk *ptrChunkToDelete = NULL;
    while(ptrChunk)
    {
        if(ptrChunk->IsAllocationChunk)
        {    
            if(ptrChunkToDelete)
            {
                free(((void *) ptrChunkToDelete));
            }
            ptrChunkToDelete = ptrChunk;
        }
        ptrChunk = ptrChunk->Next;
    }
}

void* CMemoryPool::GetMemory(const std::size_t &sMemorySize)
{
    std::size_t sBestMemBlockSize = CalculateBestMemoryBlockSize(sMemorySize);  
    SMemoryChunk* ptrChunk = NULL;
    while(!ptrChunk)
    {

        ptrChunk = FindChunkSuitableToHoldMemory(sBestMemBlockSize);

        //ptrChunk等于NULL表示内存池内存不够用
        if(!ptrChunk)
        {
            sBestMemBlockSize = MaxValue(sBestMemBlockSize, CalculateBestMemoryBlockSize(m_sMinimalMemorySizeToAllocate));
            //从OS申请更多的内存
            AllocateMemory(sBestMemBlockSize);
        }
    }
    //下面是找到可用的块(Chunk)代码
    m_sUsedMemoryPoolSize += sBestMemBlockSize;
    m_sFreeMemoryPoolSize -= sBestMemBlockSize;
    m_uiObjectCount++;
    //标记该块(Chunk)已用
    SetMemoryChunkValues(ptrChunk, sBestMemBlockSize);

    return ((void *) ptrChunk->Data);
}

void CMemoryPool::FreeMemory(void *ptrMemoryBlock, const std::size_t &sMemoryBlockSize)
{
    SMemoryChunk *ptrChunk = FindChunkHoldingPointerTo(ptrMemoryBlock);
    if(ptrChunk)
    {
        FreeChunks(ptrChunk);
    }
    else
    {
        assert(false && "ERROR : Requested Pointer not in Memory Pool");
    }
    assert((m_uiObjectCount > 0) && "ERROR : Request to delete more Memory then allocated.");
    m_uiObjectCount--;

}

void CMemoryPool::FreeChunks(SMemoryChunk *ptrChunk)
{

    SMemoryChunk *ptrCurrentChunk = ptrChunk ;
    unsigned int uiChunkCount = CalculateNeededChunks(ptrCurrentChunk->UsedSize);
    for(unsigned int i = 0; i < uiChunkCount; i++)
    {
        if(ptrCurrentChunk)
        {

            if(m_bSetMemoryData)
            {
                memset(((void *) ptrCurrentChunk->Data), FREEED_MEMORY_CONTENT, m_sMemoryChunkSize) ;
            }

            ptrCurrentChunk->UsedSize = 0;

            m_sUsedMemoryPoolSize -= m_sMemoryChunkSize;
            ptrCurrentChunk = ptrCurrentChunk->Next;
        }
    }
}

SMemoryChunk *CMemoryPool::FindChunkHoldingPointerTo(void *ptrMemoryBlock)
{
    SMemoryChunk *ptrTempChunk = m_ptrFirstChunk;
    while(ptrTempChunk)
    {
        if(ptrTempChunk->Data == ((TByte *) ptrMemoryBlock))
        {
            break;
        }
        ptrTempChunk = ptrTempChunk->Next;
    }
    return ptrTempChunk;
}

bool CMemoryPool::AllocateMemory(const std::size_t &sMemorySize)
{
    //计算可以分多少块(1000 / 128 = 8)
    unsigned int uiNeededChunks = CalculateNeededChunks(sMemorySize);

    //当内存池的初始大小为1000字节,块(Chunk)大小128字节,分8块还差24字节.怎么办?
    //解决方案:多申请24字节
    std::size_t sBestMemBlockSize = CalculateBestMemoryBlockSize(sMemorySize);

    //向OS申请内存
    TByte *ptrNewMemBlock = (TByte*) malloc(sBestMemBlockSize);

    //分配一个结构体SmemoryChunk的数组来管理内存块
    SMemoryChunk *ptrNewChunks = (SMemoryChunk*) malloc((uiNeededChunks * sizeof(SMemoryChunk))); 


    m_sTotalMemoryPoolSize += sBestMemBlockSize;
    m_sFreeMemoryPoolSize += sBestMemBlockSize;
    m_uiMemoryChunkCount += uiNeededChunks;


    if(m_bSetMemoryData)
    {
        memset(((void *) ptrNewMemBlock), NEW_ALLOCATED_MEMORY_CONTENT, sBestMemBlockSize);
    }

    return LinkChunksToData(ptrNewChunks, uiNeededChunks, ptrNewMemBlock);

}

unsigned int CMemoryPool::CalculateNeededChunks(const std::size_t &sMemorySize)
{
    float f = (float) (((float)sMemorySize) / ((float)m_sMemoryChunkSize));
    return ((unsigned int) ceil(f));
}

std::size_t CMemoryPool::CalculateBestMemoryBlockSize(const std::size_t &sRequestedMemoryBlockSize)
{
    unsigned int uiNeededChunks = CalculateNeededChunks(sRequestedMemoryBlockSize);
    return std::size_t((uiNeededChunks * m_sMemoryChunkSize));
}

bool CMemoryPool::LinkChunksToData(SMemoryChunk* ptrNewChunks, unsigned int uiChunkCount, TByte* ptrNewMemBlock)
{

    SMemoryChunk *ptrNewChunk = NULL;
    unsigned int uiMemOffSet = 0; 
    bool bAllocationChunkAssigned = false;
    for(unsigned int i = 0; i < uiChunkCount; i++)
    {    
        //建立链表
        if(!m_ptrFirstChunk)
        {
            m_ptrFirstChunk = SetChunkDefaults(&(ptrNewChunks[0]));
            m_ptrLastChunk = m_ptrFirstChunk;
            m_ptrCursorChunk = m_ptrFirstChunk;
        }
        else
        {
            ptrNewChunk = SetChunkDefaults(&(ptrNewChunks[i]));
            m_ptrLastChunk->Next = ptrNewChunk;
            m_ptrLastChunk = ptrNewChunk;
        }
        //根据块(Chunk)的大小计算下一块的内存偏移地址
        uiMemOffSet = (i * ((unsigned int) m_sMemoryChunkSize));

        //结点指向内存偏移地址
        m_ptrLastChunk->Data = &(ptrNewMemBlock[uiMemOffSet]);


        if(!bAllocationChunkAssigned)
        {
            m_ptrLastChunk->IsAllocationChunk = true;
            bAllocationChunkAssigned = true;
        }
    }


    return RecalcChunkMemorySize(m_ptrFirstChunk, m_uiMemoryChunkCount);

}


bool CMemoryPool::RecalcChunkMemorySize(SMemoryChunk *ptrChunk, unsigned int uiChunkCount)
{
    unsigned int uiMemOffSet = 0 ;
    for(unsigned int i = 0; i < uiChunkCount; i++)
    {
        if(ptrChunk)
        {
            uiMemOffSet = (i * ((unsigned int) m_sMemoryChunkSize)) ;
            ptrChunk->DataSize = (((unsigned int) m_sTotalMemoryPoolSize) - uiMemOffSet);
            ptrChunk = ptrChunk->Next;
        }
        else
        {
            assert(false && "Error : ptrChunk == NULL");
            return false;
        }
    }
    return true;
}

SMemoryChunk* CMemoryPool::SetChunkDefaults(SMemoryChunk* ptrChunk)
{
    if(ptrChunk)
    {
        ptrChunk->Data = NULL;
        ptrChunk->DataSize = 0;
        ptrChunk->UsedSize = 0;
        ptrChunk->IsAllocationChunk = false;
        ptrChunk->Next = NULL;
    }
    return ptrChunk;
}

//这里还没看明白
SMemoryChunk *CMemoryPool::FindChunkSuitableToHoldMemory(const std::size_t &sMemorySize)
{
    unsigned int uiChunksToSkip = 0;
    bool bContinueSearch = true;
    SMemoryChunk *ptrChunk = m_ptrCursorChunk; 
    for(unsigned int i = 0; i < m_uiMemoryChunkCount; i++)
    {
        if(ptrChunk)
        {
            if(ptrChunk == m_ptrLastChunk) 
            {
                ptrChunk = m_ptrFirstChunk;
            }

            if(ptrChunk->DataSize >= sMemorySize)
            {
                if(ptrChunk->UsedSize == 0)
                {
                    m_ptrCursorChunk = ptrChunk;
                    return ptrChunk;
                }
            }
            uiChunksToSkip = CalculateNeededChunks(ptrChunk->UsedSize);
            if(uiChunksToSkip == 0) uiChunksToSkip = 1;
            ptrChunk = SkipChunks(ptrChunk, uiChunksToSkip);
        }
        else
        {
            bContinueSearch = false;
        }
    }
    return NULL;
}

std::size_t CMemoryPool::MaxValue(const std::size_t &sValueA, const std::size_t &sValueB) const
{
    if(sValueA > sValueB)
    {
        return sValueA;
    }
    return sValueB;
}

void CMemoryPool::SetMemoryChunkValues(SMemoryChunk *ptrChunk, const std::size_t &sMemBlockSize)
{
    if((ptrChunk))
    {
        ptrChunk->UsedSize = sMemBlockSize;
    }
    else
    {
        assert(false && "Error : Invalid NULL-Pointer passed");
    }
}

SMemoryChunk *CMemoryPool::SkipChunks(SMemoryChunk *ptrStartChunk, unsigned int uiChunksToSkip)
{
    SMemoryChunk *ptrCurrentChunk = ptrStartChunk;
    for(unsigned int i = 0; i < uiChunksToSkip; i++)
    {
        if(ptrCurrentChunk)
        {
            ptrCurrentChunk = ptrCurrentChunk->Next;
        }
        else
        {

            assert(false && "Error : Chunk == NULL was not expected.");
            break ;
        }
    }
    return ptrCurrentChunk;
}

 测试代码:

#include "stdafx.h"

#include "CMemoryPool.h"

CMemoryPool* g_pMemPool = NULL;

class testMemoryPool
{
public:
    testMemoryPool(){
    }
    virtual ~testMemoryPool(){
    }
    void *operator new(std::size_t ObjectSize)
    {
        return g_pMemPool->GetMemory(ObjectSize) ;
    }

    void operator delete(void *ptrObject, std::size_t ObjectSize)
    {
        g_pMemPool->FreeMemory(ptrObject, ObjectSize) ;
    }

public:
    char a[512];
    bool b;
    long c;
};//sizeof(32);


int _tmain(int argc, _TCHAR* argv[])
{

    g_pMemPool = new CMemoryPool();

    testMemoryPool* test = new testMemoryPool();
    if(test){
        delete test;
        test = NULL;
    }

    if(g_pMemPool) 
        delete g_pMemPool ;

    return 0;
}

 

分享到:
评论

相关推荐

    c/c++内存池

    c/c++内存池 线程安全的c/c++内存池 线程安全的c/c++内存池 线程安全的c/c++内存池 线程安全的c/c++内存池 线程安全的c/c++内存池 线程安全的c/c++内存池 线程安全的c/c++内存池 线程安全的c/c++内存池 线程安全的c/...

    一个C++内存池实现

    本项目提供了一个C++内存池的实现,包括全局的一级内存池和每个线程独立的二级内存池。这种设计考虑到了多线程环境下的内存分配需求,确保每个线程有其私有的内存池,降低了不同线程间内存分配的冲突,提升了并发...

    C++内存池实现

    本项目提供的是一个自定义实现的C++内存池,包括文档和源代码,旨在帮助理解内存池的工作原理,并提供实际应用的示例。 在传统的C++内存分配中,`new` 和 `delete` 操作会频繁地与操作系统交互,每次申请和释放内存...

    几种内存池的实现(c/c++ 源码)

    在C/C++编程中,内存池常用于频繁创建和销毁小对象的场景,如网络编程、数据库连接等。本文将深入探讨几种内存池的实现方式及其源码分析。 1. **静态内存池**: 静态内存池在程序启动时就分配好内存,且在程序运行...

    c++内存池实例代码

    在这个实例中,"MemPool"可能包含了实现内存池的C++源代码。代码可能包含以下关键部分: 1. **内存块管理**:内存池通常包含一个数据结构(如链表或数组)来管理已分配和未分配的内存块。每个内存块都有状态标志,...

    c++ 内存池实现

    内存池C++实现源码 应用程序可以通过系统的内存分配调用预先一次性申请适当大小的内存作为一个内存池,之后应用程序自己 对内存的分配和释放则可以通过这个内存池来完成。只有当内存池大小需要动态扩展时,才需要再...

    MemoryPool:使用 C++11 的简单内存池实现

    在C++11中,我们可以利用其新引入的特性来实现一个简单的内存池。本项目就是针对这一主题的一个实践,适用于Visual Studio 2015、g++4.8和clang++3.4等编译器。 内存池的基本思想是避免频繁的系统调用,因为传统的...

    C++内存池的管理

    本文将深入探讨“C++内存池”的概念、实现原理以及如何利用它来优化内存分配。首先,我们需要理解什么是内存池。 内存池是一种内存管理策略,它预先申请一大块连续的内存,并将其划分为多个固定大小的小块,供程序...

    C++内存池完整代码memory_pool.zip

    在"memory_pool.zip"这个压缩包中,我们可以预期包含了一个实现C++内存池的源码项目。"Makefile"是用于编译和构建项目的配置文件,它定义了如何将源代码文件编译成可执行程序或库。我们可以通过运行`make`命令来编译...

    C++多线程内存池和简单的BUFFER类

    C++标准库并没有内置的内存池实现,但我们可以自定义一个。通常,内存池会包含以下组件: 1. 初始化:在程序启动时分配一大块内存。 2. 分配:从内存池中分配指定大小的内存块,如果内存池中没有合适大小的空闲块,...

    C++内存池完整代码memory_pool.rar

    在C++中,内存池通过预分配一大块连续内存,并进行精细化管理来替代标准库中的new和delete操作。下面将详细阐述内存池的工作原理以及如何实现一个简单的内存池。 内存池的基本思想是预先分配一大块内存,然后根据...

    c++内存池的使用

    c++中很好用的内存池封装,很好的解决反复new,delete带来的内存空间碎片问题,小内存,大内存都适用,里面做了直接申请空间和用内存池效率的对比,我们的项目就在用它,现分享出来,vc6上直接编译通过。

    c,c++内存池实现

    在C和C++中,内存池的实现通常涉及以下几个关键知识点: 1. **动态内存分配与释放**: C和C++中的`malloc()`和`free()`函数用于动态分配和释放内存。但是,每次调用`malloc()`时,系统都需要查找合适的空闲内存块...

    C++ 内存池的实现

    总的来说,VS2010实现的内存池管理类`BufferPool`是针对C++内存管理的一种优化手段,通过预先分配和统一管理内存,以提升程序运行效率。通过深入理解并灵活运用内存池技术,开发者可以有效地控制和优化程序的内存...

    C++ Nginx内存池源码与使用

    本文将深入探讨C++中Nginx内存池的源码与使用方法。 内存池是一种预先分配一大块连续内存,然后从中按需分配小块内存的策略。这种方式避免了系统级别的内存分配开销,提高了内存分配效率。Nginx内存池设计的核心...

    c++ 内存池技术实现

    c++ 内存池技术实现 源码 应用程序可以通过系统的内存分配调用预先一次性申请适当大小的内存作为一个内存池,之后应用程序自己对内存的分配和释放则可以通过这个内存池来完成。只有当内存池大小需要动态扩展时,才...

    C++实现循环内存池(一)

    内存池在实际的处理中起着缓存作用。即当生产者与消费者速度不一致时,需要内存池来对内容进行缓冲。 把这个两个部分分开为两个线程操作,互不干涉,中间设置一个足够大的内存池。 生产者可以不断的存入数据到内存...

    c++高性能内存池.rar

    std::allocator 是 C++标准库中提供的默认分配器,他的特点就在于我们在 使用 new 来申请内存构造新对象的时候,势必要调用类对象的默认构造函数 ...所以为了让代码直接可用,我们同样应该在内存池中设计同样的接口:

    C++内存池测试(win7 & RedHat ).zip

    总的来说,C++内存池是提高程序性能的有效手段,尤其是在多线程和大量小对象分配的场景下。理解其工作原理并根据具体操作系统的特点进行优化,是每个C++开发者需要掌握的技能。通过阅读和分析提供的测试代码,我们...

    C++简单内存池模板类实现

    自己实现的c++内存池,模板类实现,具备基础内存块,递增梯度,最大内存块等配置参数,初始化时分配好一批内存块供作用,当内存块不够使用时,已经分配内存块小于最大内存块个数,则再分配递增梯度个内存块,如果...

Global site tag (gtag.js) - Google Analytics