通常の新しいオペレーターに代わる小さなメカニズムを作成しました。基本的に、メモリのプール (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
}
}
誰かがバグや重大な問題を見つけたら、私に知らせてください。ありがとう!