C++ 内存块 快速访问内存使用(一)


    这里要说的内存块就是预先申请一块内存,然后在这块内存上快速申请固定长度的内存,还达不到内存池的功能,但可以用来做内存池,下面是代码实现,同时加了一些注释,足够解释清楚了,内部使用模板的功能,增加可适应性

    先说说下这个内存块的原理吧,首先分配出一块内存,假设这块内存要分配出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<unsigned int _NODE_SIZE_, unsigned int _NODE_COUNT_ = 8>
	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<class T>
		T* New()
		{
			return ::new(Malloc()) T();
		}

		template<class T, class T1>
		T* New( const T1& param1 )
		{
			return ::new(Malloc()) T( param1 );
		}

		template<class T, class T1, class T2, class T3>
		T* New( const T1& param1, const T2& param2, const T3& param3 )
		{
			return ::new(Malloc()) T( param1, param2, param3 );
		}

		template<class T, class T1, class T2, class T3, class T4>
		T* New( const T1& param1, const T2& param2, const T3& param3, const T4& param4 )
		{
			return ::new(Malloc()) T( param1, param2, param3, param4 );
		}

		template<class T, class T1, class T2, class T3, class T4, class T5>
		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<class T, class T1, class T2, class T3, class T4, class T5, class T6>
		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<class T, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
		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<class T, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
		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<class T, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9>
		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<class T>
		inline bool Delete( const void* p );

		// 把分配的全部回收到内存块中
		template<class T>
		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 int _NODE_SIZE_, unsigned int _NODE_COUNT_>
	unsigned char MemBlock<_NODE_SIZE_,_NODE_COUNT_>::tracememflag[MemBlock<_NODE_SIZE_,_NODE_COUNT_>::TRACE_SIZE];
#endif

	template<unsigned int _NODE_SIZE_, unsigned int _NODE_COUNT_>
	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<unsigned int _NODE_SIZE_, unsigned int _NODE_COUNT_>
	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<unsigned int _NODE_SIZE_, unsigned int _NODE_COUNT_>
	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<unsigned int _NODE_SIZE_, unsigned int _NODE_COUNT_>
	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<unsigned int _NODE_SIZE_, unsigned int _NODE_COUNT_>
	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<unsigned int _NODE_SIZE_, unsigned int _NODE_COUNT_>
	template<class T>
	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<unsigned int _NODE_SIZE_, unsigned int _NODE_COUNT_>
	template<class T>
	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<unsigned int _NODE_SIZE_, unsigned int _NODE_COUNT_>
	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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值