ページフォルトが発生しまくるのにむかついたので、
ついに作ってしまった。
とりあえず、ページフォルトの発生を抑えることが出来た。
しかし、、、体感速度はそれほど速くなっていない!!
つーことは、ディスクIOが足を引っ張っているのかねー。
自前ヒープの実装は、一方行リストで作っているんで、
小さいメモリをたくさん確保しまくる処理をすると逆に足を引っ張るかもしれない。
俺様は大きいメモリを少し確保できればいいから、これで十分だ。
#include
#include
#include
#include
struct MyHeapManage
{
DWORD size; //自分の領域
DWORD next; //自分の次まで xxx バイト
};
class MyHeap
{
public:
MyHeap(DWORD inSize)
{
DWORD size = inSize + sizeof(MyHeapManage) * (2+100);
this->BigMemory = (char*) VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
this->BigMemoryEnd = this->BigMemory + size;
if (! VirtualLock(this->BigMemory ,size ) )
{
//ロックできませんでした...
//スワップしまくるのは仕様です
}
MyHeapManage * w ;
w = (MyHeapManage *)(this->BigMemory);
w->size = 1;
w->next = 1;
//memcpy( this->BigMemory , &w , sizeof(MyHeapManage) );
w = (MyHeapManage *)(this->BigMemory + sizeof(MyHeapManage));
w->size = 0;
w->next = 0;
//memcpy( this->BigMemory + sizeof(MyHeapManage), &w , sizeof(MyHeapManage) );
}
~MyHeap()
{
VirtualUnlock(this->BigMemory , (DWORD)(this->BigMemoryEnd - this->BigMemory) );
VirtualFree(this->BigMemory, 0, MEM_RELEASE);
}
void* Alloc(int inNewSize)
{
MyHeapManage * m ;
MyHeapManage * w ;
DWORD offset = 0;
while(1)
{
//memcpy( &m , this->BigMemory + offset , sizeof(MyHeapManage) );
m = (MyHeapManage *)(this->BigMemory + offset);
if (m->next == 0)
{
break;
}
else if (m->next - m->size >= inNewSize + sizeof(MyHeapManage))
{//空いている空間を発見
DWORD newOffset = offset + sizeof(MyHeapManage) + m->size;
//空間の分割を行う
//新たに確保する部分
w = (MyHeapManage *)(this->BigMemory + newOffset);
w->size = inNewSize;
w->next = m->next - m->size - sizeof(MyHeapManage) ;
//memcpy( this->BigMemory + newOffset,&w, sizeof(MyHeapManage) );
//既存の領域の修正
w = (MyHeapManage *)(this->BigMemory + offset);
w->size = m->size;
w->next = m->size;
//memcpy( this->BigMemory + offset ,&w, sizeof(MyHeapManage) );
return this->BigMemory + newOffset + sizeof(MyHeapManage);
}
else
{
//領域に空きがないので次のブロックへ
offset = offset + m->next + sizeof(MyHeapManage);
}
}
//終端までやってきてしまった
if ( this->BigMemory + offset + sizeof(MyHeapManage) + inNewSize + sizeof(MyHeapManage) >= this->BigMemoryEnd )
{
//メモリ不足
throw std::bad_alloc();
}
w = (MyHeapManage *)(this->BigMemory + offset);
w->size = inNewSize;
w->next = inNewSize;
//memcpy( this->BigMemory + offset ,&w, sizeof(MyHeapManage) );
//新しい終端の作成
DWORD newEndOffset = offset + inNewSize + sizeof(MyHeapManage) ;
w = (MyHeapManage *)(this->BigMemory + newEndOffset);
w->size = 0;
w->next = 0;
//memcpy( this->BigMemory + newEndOffset ,&w, sizeof(MyHeapManage) );
return this->BigMemory + offset + sizeof(MyHeapManage);
}
void Free(void * ioMemory)
{
MyHeapManage * m ;
MyHeapManage * w ;
DWORD offset = 0;
DWORD beforeOffset = 0;
do
{
m = (MyHeapManage *)(this->BigMemory + offset);
//memcpy( &m , this->BigMemory + offset , sizeof(MyHeapManage) );
if (this->BigMemory + offset + sizeof(MyHeapManage) == ioMemory)
{//発見.
//自分の一つ前のデータに自分をスキップしてもらうように依頼する
w = (MyHeapManage *)(this->BigMemory + beforeOffset);
//memcpy( &w , this->BigMemory + beforeOffset , sizeof(MyHeapManage) );
w->next = w->next + sizeof(MyHeapManage) + m->next;
//memcpy( this->BigMemory + beforeOffset ,&w, sizeof(MyHeapManage) );
return ;
}
beforeOffset = offset;
offset = offset + m->next + sizeof(MyHeapManage);
}
while(m->next != 0);
//見つからない!!
return ;
}
//正当性のチェック
bool Check()
{
MyHeapManage * m ;
DWORD offset = 0;
do
{
if (this->BigMemory + offset >= this->BigMemoryEnd )
{
return false;
}
m = (MyHeapManage *)(this->BigMemory + offset);
//memcpy( &m , this->BigMemory + offset , sizeof(MyHeapManage) );
offset = offset + m->next + sizeof(MyHeapManage);
}
while(m->next != 0);
//最後のノードは サイズは 0
return m->size == 0;
}
//テスト
static void test()
{
MyHeap heap(100);
char* a = (char*)heap.Alloc(20);
sprintf(a , "buffer a");
char* b = (char*)heap.Alloc(15);
sprintf(b , "buffer b");
char* c = (char*)heap.Alloc(20);
sprintf(c , "buffer c");
assert( heap.Check() );
assert(strcmp( a , "buffer a" ) == 0);
assert(strcmp( b , "buffer b" ) == 0);
assert(strcmp( c , "buffer c" ) == 0);
heap.Free(b);
assert( heap.Check() );
//確保容量が同じなので、 newb は b の場所が再利用されるはず
char* newb = (char*)heap.Alloc(15);
assert(b == newb);
sprintf(newb , "buffer newb");
assert(strcmp( a , "buffer a" ) == 0);
assert(strcmp( c , "buffer c" ) == 0);
assert( heap.Check() );
heap.Free(newb);
assert( heap.Check() );
//サイズが大きいので、 bではなく、 c より後に記憶されるはず
char* d = (char*)heap.Alloc(20);
assert(d > c);
assert( heap.Check() );
sprintf(d , "buffer d");
assert(strcmp( a , "buffer a" ) == 0);
assert(strcmp( c , "buffer c" ) == 0);
assert(strcmp( d , "buffer d" ) == 0);
assert( heap.Check() );
//すべて開放します
heap.Free(a);
assert(strcmp( c , "buffer c" ) == 0);
heap.Free(c);
assert(strcmp( d , "buffer d" ) == 0);
heap.Free(d);
assert( heap.Check() );
//新しく確保します
char* e = (char*)heap.Alloc(100);
assert( heap.Check() );
sprintf(e , "big buffer e!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
assert(strcmp( e , "big buffer e!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" ) == 0);
assert( heap.Check() );
heap.Free(e);
assert( heap.Check() );
}
private:
char * BigMemory;
char * BigMemoryEnd;
};