内存池

1. 内存池设计

1.1 目的

在给定的内存buffer上建立内存管理机制,根据用户需求从该buffer上分配内存或者将已经分配的内存释放回buffer中。

1.2 要求

尽量减少内存碎片,平均效率高于C语言的malloc和free。

1.3 设计思路

  • 一个存储全部内存的容器
  • 一个存储正在使用的内存的容器
  • 一个存储未被使用的容器

实现


#ifndef TESTJSON_MEMORYPOOL_HPP
#define TESTJSON_MEMORYPOOL_HPP

#include <algorithm>
#include <functional>
#include <set>
#include <vector>
#include <queue>
#include <cstdlib>
#include <cxxabi.h>

template<typename T>
class MemoryPool
{
public:
    MemoryPool();

    MemoryPool(int max_size);

    virtual ~MemoryPool();

    T *alloc();

    void release(T *obj);

    void walkUsedMemList(std::function<void(T *)> func);

private:
    static int ALLOC_STEP;
    int mMaxSize;
    int mCurrentSize;

    std::queue<T *> mFreeMemList;
    std::set<T *> mUsedMemList;

    int newMemList(int size);
};

template<class T>
int MemoryPool<T>::ALLOC_STEP = 20;

template<class T>
MemoryPool<T>::MemoryPool()
{
    this->mCurrentSize = 0;
    this->mMaxSize = 0;
    this->newMemList(ALLOC_STEP);
}

template<class T>
MemoryPool<T>::MemoryPool(int max_size)
{
    this->mCurrentSize = 0;
    this->mMaxSize = max_size;
    this->newMemList(ALLOC_STEP);
}

template<class T>
MemoryPool<T>::~MemoryPool()
{
    for_each(mUsedMemList.begin(), mUsedMemList.end(), [&](T *mem)
    {
        free(mem);
    });

    int queue_size = mFreeMemList.size() ;
    for (int i = 0; i < queue_size; ++i)
    {
        auto mem = mFreeMemList.front();
        free(mem);
        mFreeMemList.pop();
    }
}

template<class T>
void MemoryPool<T>::walkUsedMemList(std::function<void(T *)> func)
{
    for_each(mUsedMemList.begin(), mUsedMemList.end(), [&](T *mem)
    {
        func(mem);
    });
}

template<class T>
int MemoryPool<T>::newMemList(int size)
{
    if (this->mMaxSize > 0)
    {
        int left = this->mMaxSize - this->mCurrentSize;
        if (left == 0)
            return 0;
        size = size < left ? size : left;
    }

    for (int i = 0; i < size; i++)
    {
        T *mem = (T *) malloc(sizeof(T));
        if (!mem)
        {
            printf("malloc failed! total size : %d \n", mCurrentSize);
            return 0;
        }
        mFreeMemList.push(mem);
    }
    this->mCurrentSize += size;

    // ???
//    printf("pool add objs : %s pool , total size : %d\n", abi::__cxa_demangle(typeid(T).name(), 0, 0, 0), mCurrentSize);
    return size;
}

template<class T>
T *MemoryPool<T>::alloc()
{
    if (mFreeMemList.empty())
    {
        if (newMemList(ALLOC_STEP) == 0)
        {
            return NULL;
        }
    }
    T *obj = mFreeMemList.front();
    mUsedMemList.insert(obj);
    mFreeMemList.pop();
    return obj;
}

template<typename T>
inline void MemoryPool<T>::release(T *obj)
{
    if (mUsedMemList.erase(obj))
    {
        mFreeMemList.push(obj);
    }
}

#endif //TESTJSON_MEMORYPOOL_HPP