问题描述:
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