メモリプールバージョン3-シングルスレッド-可変サイズオブジェクトのメモリプール

18711 ワード

#include "stdafx.h"
#include
<windows.h>
#include
<MMSystem.h>
#include
<iostream>
using namespace std;

#pragma comment(lib, "winmm.lib")

class Foo
{
public:
Foo(
int a = 0, int b = 0):m(a), n(b) {}

private:
int m;
int n;
};

class MemoryChunk
{
public:
MemoryChunk(MemoryChunk
* next, size_t reqSize)
{
m_pNext
= next;
size_t chunkSize
= reqSize > DEFAULT_CHUNK_SIZE ? reqSize : DEFAULT_CHUNK_SIZE;
m_nChunkSize
= chunkSize;
m_pMem
= new char[m_nChunkSize];
m_nBytesAlreadyAllocated
= 0;
}

~MemoryChunk() {delete m_pMem;}

void* alloc(size_t size)
{
void* pAddr = (void*)((size_t)m_pMem + m_nBytesAlreadyAllocated);
m_nBytesAlreadyAllocated
+= size;
return pAddr;
}

void free(void* doomed)
{
//do nothing
//
}

MemoryChunk
* NextMemoryChunk() const {return m_pNext;}

size_t SpaceAvailiable()
const {return m_nChunkSize - m_nBytesAlreadyAllocated;}

enum{DEFAULT_CHUNK_SIZE = 4096};

private:
MemoryChunk
* m_pNext;
void* m_pMem;
size_t m_nChunkSize;
size_t m_nBytesAlreadyAllocated;
};

class ByteMemoryPool
{
public:
ByteMemoryPool(size_t initSize
= MemoryChunk::DEFAULT_CHUNK_SIZE)
{
m_chunkList
= 0; //must set to null
ExpandStorage(initSize);
}

~ByteMemoryPool()
{
MemoryChunk
* pChunk = m_chunkList;
while (pChunk)
{
m_chunkList
= pChunk->NextMemoryChunk();
delete pChunk;
pChunk
= m_chunkList;
}
}

void* alloc(size_t reqSize)
{
if (reqSize > m_chunkList->SpaceAvailiable())
{
ExpandStorage(reqSize);
}

return m_chunkList->alloc(reqSize);
}

void free(void* doomed)
{
m_chunkList
->free(doomed);
}

private:
MemoryChunk
* m_chunkList;

void ExpandStorage(size_t reqSize)
{
MemoryChunk
* pTmp = new MemoryChunk(m_chunkList, reqSize);
m_chunkList
= pTmp;
}
};


class Foo3
{
public:
Foo3(
int a= 0, int b = 0):m_x(a), m_y(b){}
void* operator new (size_t size)
{
if (m_pPool)
return m_pPool->alloc(size);
}

void operator delete(void* doomed)
{
if (m_pPool)
m_pPool
->free(doomed);
}

static void NewMemoryPool()
{
m_pPool
= new ByteMemoryPool();
}

static void DeleteMemoryPool()
{
delete m_pPool;
}

private:
int m_x;
int m_y;

static ByteMemoryPool* m_pPool;
};

ByteMemoryPool
* Foo3::m_pPool = 0;



int main()
{
DWORD time1, time2, deltaTime;
time1
= timeGetTime();
for (int i=0; i<500; ++i)
{
Foo
* ptrArray[1000];
for (int j=0; j<1000; ++j)
{
ptrArray[j]
= new Foo;
}

for (int j=0; j<1000; ++j)
{
delete ptrArray[j];
}
}

time2
= timeGetTime();
deltaTime
= time2- time1;
cout
<<deltaTime<<endl;

Foo3::NewMemoryPool();
time1
= timeGetTime();
for (int i=0; i<500; ++i)
{
Foo3
* ptrArray[1000];
for (int j=0; j<1000; ++j)
{
ptrArray[j]
= new Foo3;
}

for (int j=0; j<1000; ++j)
{
delete ptrArray[j];
}
}

time2
= timeGetTime();
Foo3::DeleteMemoryPool();
deltaTime
= time2- time1;
cout
<<deltaTime<<endl;

return 0;
}

  
//1.メモリブロックリストの最初の要素は、メモリの割り当てに使用できるメモリブロックです.
//2.プール全体のプロファイルでは、オブジェクトを解放するたびにプールまたはスタックにメモリを返すのではなく、すべてのメモリがスタックに返されます.
//最初のブロックのみが割り当てに使用できることが規定されていたため、これらのメモリを最初のブロックに追加するとメモリが不連続になるという問題が発生します.若し
//この解放されたメモリを新しいブロックとしてプールのリストに追加すると、割り当てに使用できるメモリブロックが複数表示されます.
//解決策:プールに2つのテーブルを配置することができ、新たにリリースされたメモリブロックのチェーンテーブルを追加することができ、メモリを割り当てることができるブロックが複数ある.
//リリースされるメモリはブロックとしてこのチェーンテーブルに追加されます.新しいメモリが割り当てられた場合、このテーブルを優先して条件を満たすブロックがあるかどうかを探します.
//再配分されたチェーンテーブルに条件を満たすブロックを探して、再配分がなければ.
//3.ストレージブロックが切れた場合、プールはExpandStorageを呼び出して新しいメモリブロックを割り当てます.