nlib
heap/gameheap/gameheap_appcode.cpp

The heap systems that generally tend to be used in game programs are instantiated using nn::nlib::heap::CentralHeap.

Memory can be allocated and freed from different address spaces for each HeapHandle. It is also possible to create each heap from memory regions that have been allocated in advance using structures like arrays.

It allocates and frees memory by instantiating a HeapHandle as follows.

  1. Use HeapHandle::CreateHeap(mem, size) to create a heap in memory and return an object handle of type HeapHandle.
  2. Memory can be allocated from the heap using handle.Alloc. This is thread-safe.
  3. Memory can be returned to the heap using handle.free. This is thread-safe.
  4. The entire heap can be deleted using HeapHandle::DestroyHeap(handle).
  5. Use GetThreadDefaultHeapHandle to get the per-thread heap handle. You can set this using SetThreadDefaultHeapHandle.

Separating memory and using multiple heaps has the following advantages.

Classes that allocate memory from different heaps for each object can also be created by instantiating objects from the Factory method pattern (derived from IDisposer).

Also refer to the heap/gameheap/gameheap.h and heap/gameheap/gameheap.cpp samples.

/*--------------------------------------------------------------------------------*
Project: CrossRoad
Copyright (C)Nintendo All rights reserved.
These coded instructions, statements, and computer programs contain proprietary
information of Nintendo and/or its licensed developers and are protected by
national and international copyright laws. They may not be disclosed to third
parties or copied or duplicated in any form, in whole or in part, without the
prior written consent of Nintendo.
The content herein is highly confidential and should be handled accordingly.
*--------------------------------------------------------------------------------*/
#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 InitMyHeap() {
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 TerminateMyHeap() {
for (int i = 0; i < 3; ++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);
path_ = reinterpret_cast<char*>(path);
// DUMMY:
// Sets up vertices_ and triangles_. It may read some files.
// The regions for vertices_ and triangles_ are allocated
// from heap_handle[kGraphcisObjectHeap].
vertices_ = reinterpret_cast<float*>(h.Alloc(1024 * 3 * sizeof(float)));
triangles_ = reinterpret_cast<uint16_t*>(h.Alloc(512 * 3 * sizeof(uint16_t)));
nlib_printf(" GraphicsObject::Init end\n");
return vertices_ && triangles_;
}
private:
GraphicsObject() NLIB_NOEXCEPT : IDisposer(heap_handle[kGraphcisObjectHeap]) {
path_ = NULL;
vertices_ = NULL;
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*>(path_));
h.Free(vertices_);
h.Free(triangles_);
nlib_printf(" GraphicsObject::~GraphicsObject() end\n");
}
private:
const char* path_;
float* vertices_;
uint16_t* 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);
path_ = reinterpret_cast<char*>(path);
// DUMMY:
// Sets up wavedata_count_ and wavedata_. It may read some files.
// The regions for wavedata_ are allocated from heap_handle[kSoundObjectHeap].
wavedata_count_ = 2;
wavedata_ = (void**)h.Alloc(n * sizeof(*wavedata_));
if (!wavedata_) return false;
for (size_t i = 0; i < wavedata_count_; ++i) {
wavedata_[i] = NULL;
}
for (size_t i = 0; i < wavedata_count_; ++i) {
wavedata_[i] = h.Alloc(8192);
if (!wavedata_[i]) return false;
}
nlib_printf(" SoundObject::Init() end\n");
return true;
}
private:
SoundObject() NLIB_NOEXCEPT : IDisposer(heap_handle[kSoundObjectHeap]) {
wavedata_count_ = 0;
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*>(path_));
for (size_t i = 0; i < wavedata_count_; ++i) {
h.Free(wavedata_[i]);
}
h.Free(wavedata_);
nlib_printf(" SoundObject::~SoundObject() end\n");
}
private:
const char* path_;
size_t wavedata_count_;
void** 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");
data_ = GetHeapHandle().Alloc(1024);
if (!data_) return false;
nlib_printf(" MiscObject::Init end\n");
return true;
}
private:
explicit MiscObject(HeapHandle h) NLIB_NOEXCEPT : IDisposer(h) {
data_ = NULL;
}
virtual ~MiscObject() NLIB_NOEXCEPT NLIB_OVERRIDE {
nlib_printf(" MiscObject::~MiscObject() begin, free its data members\n");
GetHeapHandle().Free(data_);
nlib_printf(" MiscObject::~MiscObject() end\n");
}
private:
void* 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");
graphics_object_ = GraphicsObject::Create();
if (!graphics_object_ || !graphics_object_->Init(graphics_res_path)) return false;
sound_object_ = SoundObject::Create();
if (!sound_object_ || !sound_object_->Init(sound_res_path)) return false;
misc_object_ = MiscObject::Create(GetHeapHandle());
if (!misc_object_ || !misc_object_->Init()) return false;
nlib_printf(" CharacterObject::Init end\n");
return true;
}
private:
explicit CharacterObject(HeapHandle h) NLIB_NOEXCEPT : IDisposer(h) {
graphics_object_ = NULL;
sound_object_ = NULL;
misc_object_ = NULL;
}
virtual ~CharacterObject() NLIB_NOEXCEPT NLIB_OVERRIDE {
nlib_printf(" CharacterObject::~CharacterObject() begin, free its data members\n");
if (graphics_object_) graphics_object_->Destroy();
if (sound_object_) sound_object_->Destroy();
if (misc_object_) misc_object_->Destroy();
nlib_printf(" CharacterObject::~CharacterObject() end\n");
}
private:
// ChacacterObject itself from Heap0
GraphicsObject* graphics_object_; // from Heap1
SoundObject* sound_object_; // from Heap2
MiscObject* misc_object_; // 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**) {
InitMyHeap();
bool result = TestGraphicsObject();
TerminateMyHeap();
return result;
}
NLIB_MAINFUNC