最近研究了一下stl的内存分配器,现在整理了一份关于分配器的代码, 希望对大家有帮助!!
首先是动态内存分配器,代码如下:
#ifndef POOL_H_INCLUDED_GF
#define POOL_H_INCLUDED_GF
//
// 大块内存分配器
//
#ifdef _WIN32
#pragma warning(push)
#pragma warning(disable:4018) // signed/unsigned mismatch
#pragma warning(disable:4290) // exception spec ignored
#endif
#include <exception>
#include <list>
#include <algorithm>
#include <iostream>
#include "noncopy.h"
class CChunkAllocator : public Gavin::CNonCopy
{
class logic_error : public std::exception
{
public:
logic_error(const char *what):what_(what){}
const char* what() { return what_; }
private:
const char* what_;
};
// 释放仿函数, Skiller()就是生成一个临时的对象
struct SKiller
{
void operator()(char *p)
{
delete [] p;
}
};
enum pool_defaults
{
init_size = 0xfffff,
min_size = 0xf
};
public:
// 分配内存,并注册到系统中去
CChunkAllocator(size_t size = init_size) : m_nSize(size)
{
if((m_nSize - BLOCK_SZIE) < min_size)
{
throw logic_error("Initial pool size too small");
}
char* poBlock = new char[m_nSize];
if (!poBlock)
{
throw std::bad_alloc();
}
m_listMemPool.push_back(poBlock); // 资源保存
m_poMemBlocks = reinterpret_cast<SBlockHead*>(poBlock); // 第一个block块
m_poMemBlocks->m_poPrev = 0;
m_poMemBlocks->m_poNext = 0;
m_poMemBlocks->m_nFree = 1;
m_poMemBlocks->m_nSize = (m_nSize - BLOCK_SZIE);
}
~CChunkAllocator()
{
std::for_each(m_listMemPool.begin(), m_listMemPool.end(), SKiller());
}
// 分配size大小的内存
void* allocate(size_t size)
{
if(size > (m_nSize - BLOCK_SZIE))
{
throw std::bad_alloc();
}
// 如果没有足够的空间,就首先分配空间
SBlockHead* poBlock = m_poMemBlocks;
while(1)
{
// 这里好像会有死循环,这里似乎要保证申请的内存小于m_nSize的大小
while(!poBlock->m_nFree)
{
if(!poBlock->m_poNext)
{
grow(poBlock);
}
poBlock = poBlock->m_poNext;
}
if(poBlock->m_nSize < size)
{
continue;
}
break;
}
if(poBlock->m_nSize - size < 2 * BLOCK_SZIE) // 内存不足,直接浪费了?
{
poBlock->m_nFree = 0;
// 前面加了一个SBlockInfo的头,返回容易处理,注意这里的位置关系
return reinterpret_cast<char *>(poBlock) + BLOCK_SZIE;
}
else
{
// 把剩余的内存保存起来
SBlockHead * poLeftBlock = reinterpret_cast<SBlockHead *>(reinterpret_cast<char *>(poBlock)
+ size + BLOCK_SZIE);
if(poBlock->m_poNext)
{
poBlock->m_poNext->m_poPrev = poLeftBlock;
}
poLeftBlock->m_poNext = poBlock->m_poNext;
poBlock->m_poNext = poLeftBlock;
poLeftBlock->m_poPrev = poBlock;
poBlock->m_nFree = 0;
poLeftBlock->m_nSize = poBlock->m_nSize - size - BLOCK_SZIE;
poBlock->m_nSize = size;
poLeftBlock->m_nFree = 1;
return reinterpret_cast<char *>(poBlock) + BLOCK_SZIE;
}
}
// 释放内存,poMem是从allocate函数中分配的
void deallocate(void* poMem, size_t nSize = 0)
{
if(!poMem)
{
return;
}
// 得到原来的SBlockHead*
SBlockHead* poBlock = reinterpret_cast<SBlockHead *>(static_cast<char*>(poMem) - BLOCK_SZIE);
if(poBlock->m_poPrev && poBlock->m_poNext)
{
if(poBlock->m_poPrev->m_nFree && poBlock->m_poNext->m_nFree)
{
poBlock->m_poPrev->m_nSize += poBlock->m_nSize + poBlock->m_poNext->m_nSize + 2 * BLOCK_SZIE;
poBlock->m_poPrev->m_poNext = poBlock->m_poNext->m_poNext;
if(poBlock->m_poNext->m_poNext)
{
poBlock->m_poNext->m_poNext->m_poPrev = poBlock->m_poPrev;
}
return;
}
}
if(poBlock->m_poPrev)
{
// 合并内存
if(poBlock->m_poPrev->m_nFree)
{
poBlock->m_poPrev->m_nSize += (poBlock->m_nSize + BLOCK_SZIE);
poBlock->m_poPrev->m_poNext = poBlock->m_poNext;
if(poBlock->m_poNext)
{
poBlock->m_poNext->m_poPrev = poBlock->m_poPrev;
}
poBlock->m_nFree= 1;
return;
}
}
if(poBlock->m_poNext)
{
// 合并内存
if(poBlock->m_poNext->m_nFree)
{
poBlock->m_nSize += (poBlock->m_poNext->m_nSize + BLOCK_SZIE);
poBlock->m_poNext = poBlock->m_poNext->m_poNext;
if(poBlock->m_poNext)
{
poBlock->m_poNext->m_poPrev = poBlock;
}
poBlock->m_nFree= 1;
return;
}
}
poBlock->m_nFree = 1;
}
// 显示内存使用情况
void dump()
{
using namespace std;
SBlockHead *b = m_poMemBlocks;
while(1)
{
cout << "Size=" << b->m_nSize << ", free=" << b->m_nFree <<
", prev=" << b->m_poPrev << ", next=" << b->m_poNext << endl;
if(b->m_poNext)
{
b = b->m_poNext;
}
else
{
break;
}
}
}
protected:
// 释放内存
static void kill(char* p)
{
delete [] p;
}
// 增长内存一块m_nSize的内存,并加入到poOldBlock后面
void grow(SBlockHead* poOldBlock)
{
SBlockHead* poNewBlock = NULL;
char* poNewMem = new char[m_nSize];
if (!poNewMem)
{
throw std::bad_alloc();
}
m_listMemPool.push_back(poNewMem);
poNewBlock = reinterpret_cast<SBlockHead*>(poNewMem);
poNewBlock->m_poPrev = poOldBlock;
poNewBlock->m_poNext = NULL;
poNewBlock->m_nFree = 1;
poNewBlock->m_nSize = (m_nSize - BLOCK_SZIE);
poOldBlock->m_poNext = poNewBlock;
}
private:
size_t m_nSize;
std::list<char *> m_listMemPool;
// 数据块节点
struct SBlockHead
{
SBlockHead* m_poPrev; // prev指针
SBlockHead* m_poNext; // next指针
size_t m_nSize; // 块大小
int m_nFree; // 剩余数量
SBlockHead(SBlockHead* prev, SBlockHead* next, size_t size, int free) :
m_poPrev(prev), m_poNext(next), m_nSize(size), m_nFree(free)
{
}
~SBlockHead()
{
}
};
#define BLOCK_SZIE sizeof(SBlockHead)
SBlockHead* m_poMemBlocks;
};
#ifdef _WIN32
#pragma warning(pop)
#endif
#endif
根据上面的内存管理器而来的stl分配器(allocator0如下:
#ifndef POOL_ALLOCATOR_H_INCLUDED_GF
#define POOL_ALLOCATOR_H_INCLUDED_GF
#include "pool.h"
// 申明
template <typename T>class pool_allocator;
// 偏特化void
template <> class pool_allocator<void>
{
public:
typedef void* pointer;
typedef const void* const_pointer;
typedef void value_type;
template <class U>
struct rebind { typedef pool_allocator<U> other; };
};
namespace pool_alloc
{
inline void destruct(char *) {}
inline void destruct(wchar_t*) {}
template <typename T>
inline void destruct(T *t) { t->~T(); }
}
template <typename T>
class pool_allocator
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
template <class U>
struct rebind
{
typedef pool_allocator<U> other;
};
pool_allocator() {}
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const { return &x; }
// 分配函数
pointer allocate(size_type size, pool_allocator<void>::const_pointer hint = 0)
{
return static_cast<pointer>(mem_.allocate(size * sizeof(T)));
}
// for Dinkumware:
char *_Charalloc(size_type n) { return static_cast<char*>(mem_.allocate(n)); }
// end Dinkumware
template <class U> pool_allocator(const pool_allocator<U>&){}
// 释放内存
void deallocate(pointer p, size_type n)
{
mem_.deallocate(p, n);
}
void deallocate(void* p, size_type n)
{
mem_.deallocate(p, n);
}
size_type max_size() const throw() { return size_t(-1) / sizeof(value_type); }
void construct(pointer p, const T& val)
{
new(static_cast<void*>(p)) T(val);
}
void construct(pointer p)
{
new(static_cast<void*>(p)) T();
}
void destroy(pointer p) { pool_alloc::destruct(p); }
static void dump(){ mem_.dump(); };
private:
static CChunkAllocator mem_;
};
template <typename T> CChunkAllocator pool_allocator<T>::mem_;
template <typename T, typename U>
inline bool operator == (const pool_allocator<T>&, const pool_allocator<U>) { return true; }
template <typename T, typename U>
inline bool operator != (const pool_allocator<T>&, const pool_allocator<U>) { return false; }
#endif