我制作了一个小机制来替换常规的 new 运算符。基本上,我们分配一个内存池(如 16mb),当调用 new 时,返回一个偏移量,该偏移量会增长直到没有更多空间,然后我们再创建一个池。只有当池中的所有元素都被释放时,池才会被删除。
我已经测试过这个类,它工作得很好,比原来的新类快 8-15 倍。但是有一个问题:我将它合并到我的另一个规模巨大的项目中,它正常工作,除了内存使用量增长非常快。基本上不会释放池,因为其中的某些项目根本没有被删除。此外,还有许多从 STL 容器对 new(0) 的调用,我不知道它应该如何响应。
这是代码:
namespace rt
{
class pool
{
friend class alloc;
private:
unsigned int _numRecords;
unsigned int _sizeLeft;
char* _ptr;
char* _data;
};
class alloc
{
public:
alloc();
alloc(int mb);
~alloc();
void* allocate(unsigned int size);
void constructPool(unsigned int idx);
void destroyPool(unsigned int idx);
void deallocate(void* ptr);
private:
const static unsigned int _numPools = 256;
const static unsigned int _poolSize = 15*1024*1024;
const static unsigned int _poolReplaceBound = 1*1024*1024; // if 1mb or less left we can replace it
pool* _pools[_numPools];
unsigned int _curPoolIdx;
};
那是标题。这是实现:
namespace rt
{
class pool
{
friend class alloc;
private:
unsigned int _numRecords;
unsigned int _sizeLeft;
char* _ptr;
char* _data;
};
class alloc
{
public:
alloc();
alloc(int mb);
~alloc();
void* allocate(unsigned int size);
void constructPool(unsigned int idx);
void destroyPool(unsigned int idx);
void deallocate(void* ptr);
private:
const static unsigned int _numPools = 256;
const static unsigned int _poolSize = 15*1024*1024;
const static unsigned int _poolReplaceBound = 1*1024*1024; // if 1mb or less left we can replace it
pool* _pools[_numPools];
unsigned int _curPoolIdx;
};
extern alloc default_allocator;
}
#define RT_SAFE_MEM
namespace rt
{
alloc default_allocator;
alloc::alloc()
{
for(int i = 0; i < _numPools; i++) _pools[i] = NULL;
_curPoolIdx = 0;
constructPool(_curPoolIdx);
}
alloc::~alloc()
{
}
void alloc::constructPool(unsigned int idx)
{
_pools[idx] = (pool*)malloc(sizeof(pool));
_pools[idx]->_numRecords = 0;
_pools[idx]->_sizeLeft = _poolSize;
_pools[idx]->_data = (char*)calloc(_poolSize, 1);
_pools[idx]->_ptr = _pools[idx]->_data;
}
void alloc::destroyPool(unsigned int idx)
{
free(_pools[idx]->_data);
free(_pools[idx]);
_pools[idx] = NULL;
}
void* alloc::allocate(unsigned int size)
{
if(size == 0)
{
return NULL;
}
#ifdef RT_SAFE_MEM
if(size > _poolSize)
{
MessageBox(NULL, "Allocation size exceeded maximum.", "Executor", MB_OK);
return NULL;
}
if(*(_pools[_curPoolIdx]->_ptr) != 0)
{
//leak
unsigned int leaksize = strlen(_pools[_curPoolIdx]->_ptr);
char str[50];
sprintf(str, "Memory corruption detected: wrote extra %u bytes. \nExporting to corrupt.txt", leaksize);
FILE* fp = fopen("corrupt.txt", "w");
fwrite(_pools[_curPoolIdx]->_ptr, 1, leaksize, fp);
fclose(fp);
MessageBox(NULL, str, "Executor", MB_OK);
return NULL;
}
#endif
if(_pools[_curPoolIdx]->_sizeLeft <= size)
{
//not enough size in this pool
//make a new one
_curPoolIdx++;
//printf("expand");
constructPool(_curPoolIdx);
return allocate(size);
}
else
{
void* ans = (void*)_pools[_curPoolIdx]->_ptr;
_pools[_curPoolIdx]->_ptr+=size;
_pools[_curPoolIdx]->_sizeLeft-=size;
_pools[_curPoolIdx]->_numRecords++;
return ans;
}
}
void alloc::deallocate(void* ptr)
{
for(int i = 0; i <= _curPoolIdx; i++)
{
if(ptr >= _pools[i]->_data && ptr < _pools[i]->_ptr)
{
//pool i contains this object
//printf("found %d\n", i);
_pools[i]->_numRecords--;
if(_pools[i]->_numRecords == 0 && _pools[i]->_sizeLeft <= _poolReplaceBound)
{
//replace this pool
printf("replacing %d\n", i);
destroyPool(i);
if(_curPoolIdx == 0) constructPool(0);
else
{
for(int j = i; j < _numPools-1; j++)
{
_pools[j] = _pools[j+1];
}
_curPoolIdx--;
}
}
return;
}
}
#ifdef RT_SAFE_MEM
char str[50];
sprintf(str, "Attempted to deallocate foreign memory at 0x%.8X.", ptr);
MessageBox(NULL, str, "Executor", MB_OK);
#endif
}
}
如果有人发现错误或重大问题,请告诉我。谢谢!