nlib
heap/gameheap/gameheap_appcode.cpp

一般にゲームプログラムにありがちなヒープシステムをnn::nlib::heap::CentralHeapを用いて構築しています。

HeapHandle毎に異なるアドレス空間からのメモリ確保と解放を行うことができます。 それぞれのヒープは配列等の事前に確保したメモリ領域から作成することも可能です。

以下のようにHeapHandleを構築してメモリの確保、解放を行います。

  1. HeapHandle::createHeap(mem, size) によって、メモリ上にヒープを作成しHeapHandle型のオブジェクトhandleを返します。
  2. handle.alloc()によって、ヒープからメモリを割り当てることができます。スレッドセーフです。
  3. handle.free()によって、ヒープにメモリを返却することができます。スレッドセーフです。
  4. HeapHandle::destroyHeap(handle)によってヒープ全体を削除します。
  5. GetThreadDefaultHeapHandle()によって、スレッド毎のヒープハンドルを取得できます。これはSetThreadDefaultHeapHandle()を用いて設定できます。

メモリを分割して複数のヒープを利用することにより、以下のようなメリットがあります。

また、IDisposerを継承してファクトリメソッドからオブジェクトの構築をすることで、オブジェクト毎に異なるヒープからメモリの確保を行うクラスを作成することが可能です。

heap/gameheap/gameheap.hheap/gameheap/gameheap.cpp も御覧ください。

#include "gameheap.h"
using nlib_ns::heap::CentralHeap;
// heap_handle[kGraphcisObjectHeap] for the graphics objects.
// heap_handle[kSoundObjectHeap] for the sound objects.
const int kGraphcisObjectHeap = 1;
const int kSoundObjectHeap = 2;
// This sample has three 2M Bytes heaps.
// One for the graphics objects, another for the sound objects, and the rest for the rest objects.
// You also can nest heaps.
static char mymem[3][1024 * 1024 * 2];
static HeapHandle heap_handle[3];
void init_my_heap() {
nlib_printf("We split memory into 3 parts.\n");
nlib_printf("Graphics objects and Sound objects are allocated from different regions\n");
nlib_printf("\n");
for (int i = 0; i < 3; ++i) {
heap_handle[i] = HeapHandle::createHeap(&mymem[i][0], 1024 * 1024 * 2);
NLIB_ASSERT(heap_handle[i].isValid());
nlib_printf("Heap %d: [%p, %p]\n", i,
(void*)&mymem[i][0], (void*)(&mymem[i][0] + 1024 * 1024 * 2));
}
nlib_printf("GraphicsObject <---- Heap%d\n", kGraphcisObjectHeap);
nlib_printf("SoundObject <---- Heap%d\n", kSoundObjectHeap);
nlib_printf("others <---- Heap0\n"); // GetThreadDefaultHeapHandle();
nlib_printf("\n");
}
void terminate_my_heap() {
for (int i = 0; i < 8; ++i) {
HeapHandle::destroyHeap(heap_handle[i]);
}
}
class GraphicsObject : public IDisposer {
public:
static GraphicsObject* Create() {
nlib_printf(" GraphicsObject::Create begin, allocate GraphicsObject itself\n");
HeapHandle h = heap_handle[kGraphcisObjectHeap];
void* mem = h.alloc(sizeof(GraphicsObject), NLIB_ALIGNOF(GraphicsObject));
GraphicsObject* obj = new(mem)GraphicsObject();
nlib_printf(" GraphicsObject::Create end\n");
return obj;
}
bool Init(const char* resource_path) {
nlib_printf(" GraphicsObject::Init begin, allocate its data members\n");
NLIB_ASSERT(resource_path);
size_t n = strlen(resource_path);
HeapHandle h = GetHeapHandle();
void* path = h.alloc(n + 1);
if (!path) return false;
memcpy(path, resource_path, n + 1);
m_Path = reinterpret_cast<char*>(path);
// DUMMY:
// Sets up m_Vertices and m_Triangles. It may read some files.
// The regions for m_Vertices and m_Triangles are allocated
// from heap_handle[kGraphcisObjectHeap].
m_Vertices = reinterpret_cast<float*>(h.alloc(1024 * 3 * sizeof(float)));
m_Triangles = reinterpret_cast<uint16_t*>(h.alloc(512 * 3 * sizeof(uint16_t)));
nlib_printf(" GraphicsObject::Init end\n");
return m_Vertices && m_Triangles;
}
private:
GraphicsObject() NLIB_NOEXCEPT : IDisposer(heap_handle[kGraphcisObjectHeap]) {
m_Path = NULL;
m_Vertices = NULL;
m_Triangles = NULL;
}
virtual ~GraphicsObject() NLIB_NOEXCEPT NLIB_OVERRIDE {
nlib_printf(" GraphicsObject::~GraphicsObject() begin, free its data members\n");
HeapHandle h = GetHeapHandle();
h.free(const_cast<char*>(m_Path));
h.free(m_Vertices);
h.free(m_Triangles);
nlib_printf(" GraphicsObject::~GraphicsObject() end\n");
}
private:
const char* m_Path;
float* m_Vertices;
uint16_t* m_Triangles;
};
class SoundObject : public IDisposer {
public:
static SoundObject* Create() {
nlib_printf(" SoundObject::Crate() begin, allocate SoundObject itself\n");
HeapHandle h = heap_handle[kSoundObjectHeap];
void* mem = h.alloc(sizeof(SoundObject), NLIB_ALIGNOF(SoundObject));
SoundObject* obj = new(mem)SoundObject();
nlib_printf(" SoundObject::Crate() end\n");
return obj;
}
bool Init(const char* resource_path) {
nlib_printf(" SoundObject::Init() begin, allocate its data members\n");
NLIB_ASSERT(resource_path);
size_t n = strlen(resource_path);
HeapHandle h = GetHeapHandle();
void* path = h.alloc(n + 1);
if (!path) return false;
memcpy(path, resource_path, n + 1);
m_Path = reinterpret_cast<char*>(path);
// DUMMY:
// Sets up m_WaveDataCnt and m_WaveData. It may read some files.
// The regions for m_WaveData are allocated from heap_handle[kSoundObjectHeap].
m_WaveDataCnt = 2;
m_WaveData = (void**)h.alloc(n * sizeof(*m_WaveData));
if (!m_WaveData) return false;
for (size_t i = 0; i < m_WaveDataCnt; ++i) {
m_WaveData[i] = NULL;
}
for (size_t i = 0; i < m_WaveDataCnt; ++i) {
m_WaveData[i] = h.alloc(8192);
if (!m_WaveData[i]) return false;
}
nlib_printf(" SoundObject::Init() end\n");
return true;
}
private:
SoundObject() NLIB_NOEXCEPT : IDisposer(heap_handle[kSoundObjectHeap]) {
m_WaveDataCnt = 0;
m_WaveData = NULL;
}
virtual ~SoundObject() NLIB_NOEXCEPT NLIB_OVERRIDE {
nlib_printf(" SoundObject::~SoundObject() begin, free its data members\n");
HeapHandle h = GetHeapHandle();
h.free(const_cast<char*>(m_Path));
for (size_t i = 0; i < m_WaveDataCnt; ++i) {
h.free(m_WaveData[i]);
}
h.free(m_WaveData);
nlib_printf(" SoundObject::~SoundObject() end\n");
}
private:
const char* m_Path;
size_t m_WaveDataCnt;
void** m_WaveData;
};
class MiscObject : public IDisposer {
public:
static MiscObject* Create(HeapHandle h) {
nlib_printf(" MiscObject::Create begin, allocate MiscObject itself\n");
void* mem = h.alloc(sizeof(MiscObject), NLIB_ALIGNOF(MiscObject));
if (!mem) return NULL;
MiscObject* obj = new(mem)MiscObject(h);
nlib_printf(" MiscObject::Create end\n");
return obj;
}
bool Init() {
nlib_printf(" MiscObject::Init begin, allocate its data members\n");
m_Data = GetHeapHandle().alloc(1024);
if (!m_Data) return false;
nlib_printf(" MiscObject::Init end\n");
return true;
}
private:
explicit MiscObject(HeapHandle h) NLIB_NOEXCEPT : IDisposer(h) {
m_Data = NULL;
}
virtual ~MiscObject() NLIB_NOEXCEPT NLIB_OVERRIDE {
nlib_printf(" MiscObject::~MiscObject() begin, free its data members\n");
GetHeapHandle().free(m_Data);
nlib_printf(" MiscObject::~MiscObject() end\n");
}
private:
void* m_Data;
};
class CharacterObject : public IDisposer {
public:
static CharacterObject* Create() {
nlib_printf(" CharacterObject::Create begin, allocate CharacterObject itself\n");
HeapHandle h = GetThreadDefaultHeapHandle();
void* mem = h.alloc(sizeof(CharacterObject), NLIB_ALIGNOF(CharacterObject));
CharacterObject* obj = new(mem)CharacterObject(h);
nlib_printf(" CharacterObject::Create end\n");
return obj;
}
bool Init(const char* graphics_res_path, const char* sound_res_path) {
nlib_printf(" CharacterObject::Init begin\n");
m_GraphicsObject = GraphicsObject::Create();
if (!m_GraphicsObject || !m_GraphicsObject->Init(graphics_res_path)) return false;
m_SoundObject = SoundObject::Create();
if (!m_SoundObject || !m_SoundObject->Init(sound_res_path)) return false;
m_MiscObject = MiscObject::Create(GetHeapHandle());
if (!m_MiscObject || !m_MiscObject->Init()) return false;
nlib_printf(" CharacterObject::Init end\n");
return true;
}
private:
explicit CharacterObject(HeapHandle h) NLIB_NOEXCEPT : IDisposer(h) {
m_GraphicsObject = NULL;
m_SoundObject = NULL;
m_MiscObject = NULL;
}
virtual ~CharacterObject() NLIB_NOEXCEPT NLIB_OVERRIDE {
nlib_printf(" CharacterObject::~CharacterObject() begin, free its data members\n");
if (m_GraphicsObject) m_GraphicsObject->Destroy();
if (m_SoundObject) m_SoundObject->Destroy();
if (m_MiscObject) m_MiscObject->Destroy();
nlib_printf(" CharacterObject::~CharacterObject() end\n");
}
private:
// ChacacterObject itself from Heap0
GraphicsObject* m_GraphicsObject; // from Heap1
SoundObject* m_SoundObject; // from Heap2
MiscObject* m_MiscObject; // from Heap0
};
bool TestGraphicsObject() {
SetThreadDefaultHeapHandle(heap_handle[0]);
CharacterObject* cobj = CharacterObject::Create();
if (!cobj || !cobj->Init("graphics_resource.bin", "sound_resource.bin")) {
nlib_printf("cobj cannot be initialized\n");
return false;
}
cobj->Destroy();
if (!heap_handle[0].isClean()) {
// it is due to someone, or a chief programmer.
nlib_printf("!!!!! Leak at Heap0 !!!!!\n");
heap_handle[0].freeAll(); // force to free the leaked memory.
return false;
}
if (!heap_handle[1].isClean()) {
// it is due to graphics programmers.
nlib_printf("!!!!! Leak at Heap1 !!!!!\n");
heap_handle[1].freeAll(); // force to free the leaked memory.
return false;
}
if (!heap_handle[2].isClean()) {
// it is due to sound programmers.
nlib_printf("!!!!! Leak at Heap2 !!!!!\n");
heap_handle[2].freeAll(); // force to free the leaked memory.
return false;
}
return true;
}
static bool SampleMain(int, char**) {
init_my_heap();
bool result = TestGraphicsObject();
terminate_my_heap();
return result;
}
NLIB_MAINFUNC