最近研究了一下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;
// 偏特化voidtemplate <> 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