首页 > 代码库 > 定长单元的批次内存缓存池的简洁实现

定长单元的批次内存缓存池的简洁实现

问题描述:

1.内存管理计算机编程中一个基本问题,其目的在于:

 1)一次可分配多个单元块,缓存维护,以改善反复的小对象申请的性能开销;

2) 管理以分配的内存,有效减少碎片的产生;

3) 保证软件使用的内存透明,了解峰值,了解使用情况,便于优化查错;

2.常用的内存管理机制有以下:

1) 变长块,依靠链表维护,一个节点一块申请了的内存,内存块大小不等,等接到一个申请时,先查维护的链表,若有可从链表取出。这种方法有很多缺点:1,当申请的内存块要遍历链表节点找到大小合适的块,最坏情况下需要把链表所有节点遍历一遍,2.造成浪费,当从链表拿到块的大小远大于所需时,造成浪费;

 2)定长单元,系统维护一个内存链表的数组,数组每项对应一个等长的多个内存单元,一次分配好。当申请到来时, 先根据申请尺寸确定对应的数组项,然后从链表头上返回所需内存节点,归还时可加尾部或者头部;

3.本文按定长单元的思想实现,实现方法由于利用了STL vector数组充当内存维护所需的链表数组,所以程序实现很简洁;

4. 本文内存池接口和系统内存操作接口做了性能上的比较;


程序代码:

#ifndef _MEMORY_BLOCK_CACHE_H_
#define _MEMORY_BLOCK_CACHE_H_

#include <stdlib.h>
#include <vector>

#include "windows.h"


#define ALIGN( size, bits )  ( ( ( ( size - 1 ) >> bits ) + 1 ) << bits )


/*
* memory pool fixed length block 
*
*
*/
class MemoryBlockCache
{
public:
	static const int MAXBLOCK = 256;
	static const int MALLOCKSIZE = 4096;
	static const int DEFAULTBASELEN = 4;

	typedef struct tagMemStatInfo
	{
		char*   allocMem;
		size_t  allocSize;

		tagMemStatInfo():allocMem(0),allocSize(0)
		{

		}

		tagMemStatInfo( char* mem, size_t size ):allocMem(mem),
			           allocSize(size)
		{

		}

	}MemStatInfo, *pMemStatInfo;



	/*
	*
	*
	*/
	MemoryBlockCache( size_t baseLen =  DEFAULTBASELEN ):m_pool(0),
		             m_poolSize(0), m_baseLen(baseLen),
					 m_memStat()
	{
		Init( m_baseLen );
	}


	/*
	*
	*
	*/
	~MemoryBlockCache()
	{
		Release();
	}


	/*
	* Release all memory allocated
	*
	*/
	void Release()
	{
		std::vector<MemStatInfo>::iterator iter = m_memStat.begin();
		while( iter != m_memStat.end() )
		{
			free( iter->allocMem );
			++iter;
		}

		for( size_t i = 0; i < m_poolSize; i++ )
		{
			m_pool[i].clear();
		}
	}


	/*
	* get memory for given length from cahce array or os
	*
	*/
	void* Malloc( size_t len )
	{
		assert( len > 0 );
		size_t size = ALIGN( len, 2 );
		if( size > MAXBLOCK )
		{
			return malloc(size);
		}
		
		if( !m_pool[size].size() )
		{
			char* buf = (char*)malloc( MALLOCKSIZE );
			size_t blockNums = MALLOCKSIZE / size;
            
			m_pool[size].reserve( blockNums );
			for( size_t i = 0; i < blockNums; i++ )
			{
				m_pool[size].push_back( buf + i * size );
			}

			m_memStat.push_back( MemStatInfo( buf, MALLOCKSIZE ) );

		}

		char* res = m_pool[size].back();
		m_pool[size].pop_back();

		return res;
	}


	/*
	* give back memory to cache or os
	*
	*/
	void Free( void* mem, size_t len )
	{
		assert( len > 0 );
		size_t size = ALIGN( len, 2 );
		if( size > MAXBLOCK )
		{
			return free( mem );
		}

		m_pool[size].push_back( (char*)mem );
	}

private:

	/*
	*
	*
	*/
	void Init( size_t baseLen )
	{
		m_poolSize = MAXBLOCK / baseLen;
		m_pool = new std::vector<char*>[m_poolSize];
	}

private:
	std::vector<char*>  *m_pool;      // memory block array
	size_t               m_poolSize;  // the size of memory block array
	size_t               m_baseLen;   // 
	std::vector<MemStatInfo> m_memStat;

	
};

//test object one
typedef struct tagBlockTestObj
{
	int first;
	int second;

	tagBlockTestObj():first(0), second(0)
	{

	}

	tagBlockTestObj( int i, int j ):first(i), second(j)
	{

	}
}BlockTestObj, *pBlockTestObj;


// test object two
typedef struct tagBlockTestExtObj
{
	int first;
	int second;
	std::string  name;

	tagBlockTestExtObj():first(0), second(0)
	{

	}

	tagBlockTestExtObj( int i, int j, const char* str ):first(i), second(j), name( str )
	{

	}

}BlockTestExtObj, *pBlockTestExtObj;


/*
* Test os memory operation
*
*/
void TestOSMemory()
{
	unsigned long start = GetTickCount();

	const int len = 2000000;
	int halfLen = len / 2;

	pBlockTestObj* objs = new pBlockTestObj[len];
	pBlockTestExtObj* objExts = new pBlockTestExtObj[len];
	for( int i = 0; i < len; i++ )
	{
		objs[i] = new BlockTestObj( i, i );
		objExts[i] = new BlockTestExtObj( i, i, "test" );
		delete objs[i];
		delete objExts[i];
		
	}

	
	
	unsigned long interval = GetTickCount() - start;
	printf(" system call consume time  %d for memory operation \n", interval );

	delete [] objs;
	delete [] objExts;
}

/*
*Test memory pool 
*
*
*/
void TestMemoryBlock()
{
	unsigned long start = GetTickCount();

	const int len = 2000000;
	int halfLen = len / 2;

	MemoryBlockCache memPool;
	pBlockTestObj* objs = new pBlockTestObj[len];
	pBlockTestExtObj* objExts = new pBlockTestExtObj[len];
	for( int i = 0; i < len; i++ )
	{
		void* buf = memPool.Malloc( sizeof(BlockTestObj) );
		objs[i] = new (buf) BlockTestObj( i, i );

		buf = memPool.Malloc( sizeof(BlockTestExtObj) );
		objExts[i] = new (buf) BlockTestExtObj( i, i, "test" );

		memPool.Free( buf, sizeof(BlockTestObj) );

		memPool.Free( buf, sizeof(BlockTestExtObj) );
		
	}


	unsigned long interval = GetTickCount() - start;
	printf(" memory pool call consume time  %d for memory operation \n", interval );

	delete [] objs;
	delete [] objExts;
}


/*
*Test interface for memory operation
*
*
*/
void TestSuiteMemoryBlock()
{

	TestMemoryBlock();
	TestOSMemory();
}

#endif 



compile and run in visual studio 2005