这里要说的内存块就是预先申请一块内存,然后在这块内存上快速申请固定长度的内存,还达不到内存池的功能,但可以用来做内存池,下面是代码实现,同时加了一些注释,足够解释清楚了,内部使用模板的功能,增加可适应性
先说说下这个内存块的原理吧,首先分配出一块内存,假设这块内存要分配出n个等大小的node,初始状态下第一个node会记录第二个node的地址,第二个记录第三个的,以此类推形成一个链表,这样就是对链表进行操作了,需要注意的是由于一个node需要记录另一个node的地址,所以node的大小必须大于一个指针的大小,在这个内存块中通过枚举做了这个工作,分配和回收函数通过对链表的操作来进行工作,简单验证了下,功能正常,要是大量申请和销毁内存速度相当可以,可以拿来做内存池使用
同时我还用另一种方式实现了内存块,效率也相当高,C++ 内存块 快速访问内存使用(二),不知道这里面是否还有没有考虑清楚的bug,希望牛人看完后给个评论
/*
============================================================================================
内存块 非线程安全
原理:
每个未使用的node记录某个未使用的node的位置 形成一个链表
要求元素的大小必须大于等于一个指针的大小 内部会自动调剂这个大小
每次操作都要充分考虑没有分配的内存
调用Malloc需要调用Free销毁 调用New需要调用Delete来销毁
使用New或者Delete函数 存在一些类型构造和析构的回调 不要在析构的回调中调用无参的Delete
在无参的Delete防止析构回调再次使用内存块分配和释放 做了一些处理
使用TRACE_MEM_BLOCK可以开启内存块一些信息的追踪
add 2013.11.22 by yuwf
Copyright (c), ...
=============================================================================================
*/
#ifndef _PALANTIR_MEM_BLOCK_H
#define _PALANTIR_MEM_BLOCK_H
#include "PLTTrace.h"
namespace Palantir
{
#ifdef PALANTIR_TRACE
#ifndef TRACE_MEM_BLOCK
#define TRACE_MEM_BLOCK
#endif
#endif
// 每个未使用的node记录某个未使用的node的位置 故而NODE_SIZE必须大于一个指针的大小
template
struct MemBlock
{
enum
{
NODE_SIZE = _NODE_SIZE_ >= sizeof(void*) ? _NODE_SIZE_ : sizeof(void*), // node的大小 最小是一个指针的大小
NODE_COUNT = _NODE_COUNT_ == 0 ? 8 : _NODE_COUNT_, // node的个数
TRACE_SIZE = NODE_SIZE*2, // 用两个node的大小跟踪
};
MemBlock();
~MemBlock();
// 分配一块内存
inline void* Malloc();
// p 必须是从这个block上malloc获取的
// 返回值表示删除成功
inline bool Free( const void* p );
// 把分配的全部回收到内存块中
inline void Free();
// 基于类型的函数
template
T* New()
{
return ::new(Malloc()) T();
}
template
T* New( const T1& param1 )
{
return ::new(Malloc()) T( param1 );
}
template
T* New( const T1& param1, const T2& param2, const T3& param3 )
{
return ::new(Malloc()) T( param1, param2, param3 );
}
template
T* New( const T1& param1, const T2& param2, const T3& param3, const T4& param4 )
{
return ::new(Malloc()) T( param1, param2, param3, param4 );
}
template
T* New( const T1& param1, const T2& param2, const T3& param3, const T4& param4, const T5& param5 )
{
return ::new(Malloc()) T( param1, param2, param3, param4, param5 );
}
template
T* New( const T1& param1, const T2& param2, const T3& param3, const T4& param4, const T5& param5, const T6& param6 )
{
return ::new(Malloc()) T( param1, param2, param3, param4, param5, param6 );
}
template
T* New( const T1& param1, const T2& param2, const T3& param3, const T4& param4, const T5& param5, const T6& param6, const T7& param7 )
{
return ::new(Malloc()) T( param1, param2, param3, param4, param5, param6, param7 );
}
template
T* New( const T1& param1, const T2& param2, const T3& param3, const T4& param4, const T5& param5, const T6& param6, const T7& param7, const T8& param8 )
{
return ::new(Malloc()) T( param1, param2, param3, param4, param5, param6, param7, param8 );
}
template
T* New( const T1& param1, const T2& param2, const T3& param3, const T4& param4, const T5& param5, const T6& param6, const T7& param7, const T8& param8, const T9& param9 )
{
return ::new(Malloc()) T( param1, param2, param3, param4, param5, param6, param7, param8, param9 );
}
// p是T类型 会调用 p->~T()
template
inline bool Delete( const void* p );
// 把分配的全部回收到内存块中
template
inline void Delete();
// 判断指针是否是这个block上的
inline bool Is_From(const void* p ) const;
// 已使用的数量
inline unsigned int Used_Count() const { return NODE_COUNT - free_num; };
// 未使用的数量
inline unsigned int Free_Count() const { return free_num; };
// 是否分配完毕
inline bool Is_Full() const { return free_num == 0 ; }
// 是否未使用
inline bool Is_Not_Use() const { return free_num == NODE_COUNT; }
protected:
// 没必要支持拷贝
MemBlock( const MemBlock& ) {};
MemBlock& operator = ( const MemBlock& ) { return *this; };
#pragma pack(1) //设置1字节对齐
// 表示一个node
struct free_node
{
char buffer[NODE_SIZE]; // 一个node占据的大小
void setnext( free_node* pnext )
{
if ( pnext == nullptr )
memset( buffer, 0, sizeof(free_node*) );
else
memcpy( buffer, &pnext, sizeof(free_node*) );
}
free_node* getnext()
{
free_node* p = nullptr;
memcpy( &p, &buffer[0], sizeof(free_node*) );
return p;
}
};
#pragma pack() //取消设置的字节对齐方式
unsigned int free_num; // 未分配的个数 用户快速判断是否还有空间
free_node* cur_free_node; // 当前空的node
free_node buffer[NODE_COUNT]; // 所有的node
#ifdef TRACE_MEM_BLOCK
unsigned char tracemem[TRACE_SIZE]; // 用来追踪这个块是否写超了
static unsigned char tracememflag[TRACE_SIZE];
#endif
};
// ================ 实现部分 =====================
#ifdef TRACE_MEM_BLOCK
template
unsigned char MemBlock<_NODE_SIZE_,_NODE_COUNT_>::tracememflag[MemBlock<_NODE_SIZE_,_NODE_COUNT_>::TRACE_SIZE];
#endif
template
MemBlock<_NODE_SIZE_,_NODE_COUNT_>::MemBlock() : free_num(NODE_COUNT), cur_free_node(&buffer[0])
{
for ( int i = 1; i < NODE_COUNT; ++i )
{
buffer[i-1].setnext( &buffer[i] );
}
buffer[NODE_COUNT-1].setnext( nullptr );
#ifdef TRACE_MEM_BLOCK
memcpy( tracemem, tracememflag, sizeof(tracemem) );
#endif
}
template
MemBlock<_NODE_SIZE_,_NODE_COUNT_>::~MemBlock()
{
#ifdef TRACE_MEM_BLOCK
// 用位记录是否分配出去 0标示分配出去了 1标示未分配
char freenodes[ (NODE_COUNT%8 == 0 ? NODE_COUNT : NODE_COUNT+(8-NODE_COUNT%8))/8 ] = {0};
free_node* cur_node = cur_free_node;
while ( cur_node )
{
int index = ((uintptr_t)cur_node - (uintptr_t)&buffer[0])/sizeof(free_node);
freenodes[index/8] |= 1 << (7-index%8);
cur_node = cur_node->getnext();
}
// 调用析构函数
for ( int i = 0; i < NODE_COUNT; ++i )
{
if ( !(freenodes[i/8] & ( 1 << (7-i%8) ) ) )
{
PLT_Trace( "%s 分配出去的内存没有收回 %p\n", __FUNCTION__, &buffer[i] );
}
}
if ( memcmp( tracemem, tracememflag, sizeof(tracemem) ) != 0 )
{
PLT_Trace( "%s 内存块写超了\n", __FUNCTION__ );
}
#endif
}
template
inline void* MemBlock<_NODE_SIZE_,_NODE_COUNT_>::Malloc()
{
if ( cur_free_node == nullptr )
{
return nullptr;
}
void* pnode = cur_free_node;
cur_free_node = cur_free_node->getnext();
--free_num;
return pnode;
}
template
inline bool MemBlock<_NODE_SIZE_,_NODE_COUNT_>::Free( const void* p )
{
if ( free_num == NODE_COUNT )
{
#ifdef TRACE_MEM_BLOCK
PLT_Trace( "%s 内存块没有往外分配任何元素\n", __FUNCTION__ );
#endif
return false;
}
if ( (uintptr_t)p < (uintptr_t)&buffer[0] || (uintptr_t)p > (uintptr_t)&buffer[NODE_COUNT-1] )
{
#ifdef TRACE_MEM_BLOCK
PLT_Trace( "%s 指针并不是block分配出去的 buffer.begin=%p, buffer.end=%p p=%p\n", __FUNCTION__, &buffer[0], &buffer[NODE_COUNT-1], p );
#endif
return false;
}
if( ((uintptr_t)p - (uintptr_t)&buffer[0])%sizeof(free_node) != 0 )
{
#ifdef TRACE_MEM_BLOCK
PLT_Trace( "%s 指针存在这个block上,但不在一个分配的位置 buffer.begin=%p, buffer.end=%p p=%p\n", __FUNCTION__, &buffer[0], &buffer[NODE_COUNT-1], p );
#endif
return false;
}
free_node* cur_node = cur_free_node;
while ( cur_node )
{
if ( cur_node == p )
{
#ifdef TRACE_MEM_BLOCK
PLT_Trace( "%s 指针存在这个block上,但这个位置并没有分配出去 buffer.begin=%p, buffer.end=%p p=%p\n", __FUNCTION__, &buffer[0], &buffer[NODE_COUNT-1], p );
#endif
return false;
}
cur_node = cur_node->getnext();
}
#ifdef TRACE_MEM_BLOCK
if ( memcmp( tracemem, tracememflag, sizeof(tracemem) ) != 0 )
{
PLT_Trace( "%s 内存块写超了\n", __FUNCTION__ );
}
#endif
free_node* pnode = (free_node*)p;
pnode->setnext( cur_free_node );
cur_free_node = pnode;
++free_num;
return true;
}
template
inline void MemBlock<_NODE_SIZE_,_NODE_COUNT_>::Free()
{
if ( free_num == NODE_COUNT )
{
return;
}
#ifdef TRACE_MEM_BLOCK
if ( memcmp( tracemem, tracememflag, sizeof(tracemem) ) != 0 )
{
PLT_Trace( "%s 内存块写超了\n", __FUNCTION__ );
}
#endif
for ( int i = 1; i < NODE_COUNT; ++i )
{
buffer[i-1].setnext( &buffer[i] );
}
buffer[NODE_COUNT-1].setnext( nullptr );
cur_free_node = &buffer[0];
free_num = NODE_COUNT;
}
template
template
inline bool MemBlock<_NODE_SIZE_,_NODE_COUNT_>::Delete( const void* p )
{
if ( free_num == NODE_COUNT )
{
#ifdef TRACE_MEM_BLOCK
PLT_Trace( "%s 内存块没有分配任何元素\n", __FUNCTION__ );
#endif
return false;
}
if ( (uintptr_t)p < (uintptr_t)&buffer[0] || (uintptr_t)p > (uintptr_t)&buffer[NODE_COUNT-1] )
{
#ifdef TRACE_MEM_BLOCK
PLT_Trace( "%s 指针并不是block分配出去的 buffer.begin=%p, buffer.end=%p p=%p\n", __FUNCTION__, &buffer[0], &buffer[NODE_COUNT-1], p );
#endif
return false;
}
if( ((uintptr_t)p - (uintptr_t)&buffer[0])%sizeof(free_node) != 0 )
{
#ifdef TRACE_MEM_BLOCK
PLT_Trace( "%s 指针存在这个block上,但不在一个分配的位置 buffer.begin=%p, buffer.end=%p p=%p\n", __FUNCTION__, &buffer[0], &buffer[NODE_COUNT-1], p );
#endif
return false;
}
free_node* cur_node = cur_free_node;
while ( cur_node )
{
if ( cur_node == p )
{
#ifdef TRACE_MEM_BLOCK
PLT_Trace( "%s 指针存在这个block上,但这个位置并没有分配出去 buffer.begin=%p, buffer.end=%p p=%p\n", __FUNCTION__, &buffer[0], &buffer[NODE_COUNT-1], p );
#endif
return false;
}
cur_node = cur_node->getnext();
}
#ifdef TRACE_MEM_BLOCK
if ( memcmp( tracemem, tracememflag, sizeof(tracemem) ) != 0 )
{
PLT_Trace( "%s 内存块写超了\n", __FUNCTION__ );
}
#endif
T* pobj = (T*)p;
pobj->~T(); // 这里相当于有回调 可能会存在在回调中调用同一个内存块创建和删除node
// 其实没关系 只要在这个回调中不重复删除自己(pobj)(若在析构函数中在删除自己 系统提供的delete也会崩掉) 就不会存在任何问题
// 因为本函数中只有下面的代码会修改这个内存块的变量
// 若在析构回调中调用无参的Delete,则会出现重复调用~T()的情况
if ( free_num == NODE_COUNT ) // 防止在析构回调中调用了那个无参的Delete
{
#ifdef TRACE_MEM_BLOCK
PLT_Trace( "%s 出现了不可预知的错误\n", __FUNCTION__ );
#endif
return false;
}
free_node* pnode = (free_node*)p;
pnode->setnext( cur_free_node );
cur_free_node = pnode;
++free_num;
return true;
}
template
template
inline void MemBlock<_NODE_SIZE_,_NODE_COUNT_>::Delete()
{
if ( free_num == NODE_COUNT )
{
return;
}
#ifdef TRACE_MEM_BLOCK
if ( memcmp( tracemem, tracememflag, sizeof(tracemem) ) != 0 )
{
PLT_Trace( "%s 内存块写超了\n", __FUNCTION__ );
}
#endif
// 用位记录是否分配出去 0标示分配出去了 1标示未分配
char freenodes[ (NODE_COUNT%8 == 0 ? NODE_COUNT : NODE_COUNT+(8-NODE_COUNT%8))/8 ] = {0};
free_node* cur_node = cur_free_node;
// 首先修改下面两个值 防止下面的析构函数再次使用内存块分配和释放node
cur_free_node = nullptr;
free_num = NODE_COUNT;
while ( cur_node )
{
int index = ((uintptr_t)cur_node - (uintptr_t)&buffer[0])/sizeof(free_node);
freenodes[index/8] |= 1 << (7-index%8);
cur_node = cur_node->getnext();
}
// 调用析构函数
for ( int i = 0; i < NODE_COUNT; ++i )
{
if ( !(freenodes[i/8] & ( 1 << (7-i%8) ) ) )
{
T* pobj = (T*)(&buffer[i]);
pobj->~T();
}
}
// 复位
for ( int i = 1; i < NODE_COUNT; ++i )
{
buffer[i-1].setnext( &buffer[i] );
}
buffer[NODE_COUNT-1].setnext( nullptr );
cur_free_node = &buffer[0];
free_num = NODE_COUNT;
}
template
inline bool MemBlock<_NODE_SIZE_,_NODE_COUNT_>::Is_From( const void* p ) const
{
if ( (uintptr_t)p < (uintptr_t)&buffer[0] || (uintptr_t)p > (uintptr_t)&buffer[NODE_COUNT-1] )
{
return false;
}
if( ((uintptr_t)p - (uintptr_t)&buffer[0])%sizeof(free_node) != 0 )
{
#ifdef TRACE_MEM_BLOCK
PLT_Trace( "%s 指针存在这个block上,但不在一个分配的位置 buffer.begin=%p, buffer.end=%p p=%p\n", __FUNCTION__, &buffer[0], &buffer[NODE_COUNT-1], p );
#endif
return false;
}
if ( free_num == NODE_COUNT )
{
#ifdef TRACE_MEM_BLOCK
PLT_Trace( "%s 内存块没有往外分配任何元素\n", __FUNCTION__ );
#endif
return false;
}
free_node* cur_node = cur_free_node;
while ( cur_node )
{
if ( cur_node == p )
{
#ifdef TRACE_MEM_BLOCK
PLT_Trace( "%s 指针存在这个block上,但这个位置并没有分配出去 buffer.begin=%p, buffer.end=%p p=%p\n", __FUNCTION__, &buffer[0], &buffer[NODE_COUNT-1], p );
#endif
return false;
}
cur_node = cur_node->getnext();
}
#ifdef TRACE_MEM_BLOCK
if ( memcmp( tracemem, tracememflag, sizeof(tracemem) ) != 0 )
{
PLT_Trace( "%s 内存块写超了\n", __FUNCTION__ );
}
#endif
return true;
}
}
#endif