nlib
heap/replace_malloc/replace_malloc.cpp

nlib_malloc(), nlib_free()等をnmalloc/nfreeを利用する実装に置き換えたり、new/deleteを置き換えるサンプルです。

なお、 NMalloc.hNLIB_REPLACE_MALLOC_NEWというマクロが定義されていて、このサンプルで行っていることをより簡単に行うことが可能です。

/*---------------------------------------------------------------------------*
Project: CrossRoad
Copyright (C)2012-2016 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. 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.
*---------------------------------------------------------------------------*/
#include <new>
#include <vector>
#include "nn/nlib/Config.h"
#if 1
// They must be C Linkage!
extern "C" {
// In Cygwin, you cannot override the implementation
// because nlib_malloc is not weak symbol.
void* nlib_malloc(size_t n) {
// nlib_printf("calling nmalloc %" PRIuS "\n", n);
return nmalloc(n);
}
void nlib_free(void* p) {
// nlib_printf("calling nfree %p\n", p);
nfree(p);
}
void* nlib_calloc(size_t nmemb, size_t size) { return ncalloc(nmemb, size); }
void* nlib_realloc(void* ptr, size_t size) { return nrealloc(ptr, size); }
void* nlib_memalign(size_t alignment, size_t size) {
// The order must be reverse here...
return nmalloc_aligned(size, alignment);
}
void nlib_free_size(void* ptr, size_t size) { nfree_size(ptr, size); }
}
// Overrides new/delete.
#ifndef NN_PLATFORM_CTR
void* operator new(size_t size) { return nlib_malloc(size); }
void operator delete(void* ptr) NLIB_NOEXCEPT { nlib_free(ptr); }
void* operator new(size_t size, const std::nothrow_t&) NLIB_NOEXCEPT { return nlib_malloc(size); }
void operator delete(void* ptr, const std::nothrow_t&) NLIB_NOEXCEPT { nlib_free(ptr); }
void* operator new[](size_t size) { return nlib_malloc(size); }
void operator delete [](void* ptr) NLIB_NOEXCEPT { nlib_free(ptr); }
void* operator new[](size_t size, const std::nothrow_t&) NLIB_NOEXCEPT { return nlib_malloc(size); }
void operator delete[](void* ptr, const std::nothrow_t&) NLIB_NOEXCEPT { nlib_free(ptr); }
// for C++14 sized deallocation
void
operator delete(void* ptr, size_t size) NLIB_NOEXCEPT {
nlib_free_size(ptr, size);
}
void operator delete(void* ptr, size_t size, const std::nothrow_t&) NLIB_NOEXCEPT {
nlib_free_size(ptr, size);
}
void operator delete[](void* ptr, size_t size) NLIB_NOEXCEPT { nlib_free_size(ptr, size); }
void operator delete[](void* ptr, size_t size, const std::nothrow_t&) NLIB_NOEXCEPT {
nlib_free_size(ptr, size);
}
#else
void* operator new(size_t size) throw(std::bad_alloc) { return nlib_malloc(size); }
void operator delete(void* ptr) throw() { nlib_free(ptr); }
void* operator new(size_t size, const std::nothrow_t&) throw() { return nlib_malloc(size); }
void* operator new[](size_t size) throw(std::bad_alloc) { return nlib_malloc(size); }
void operator delete[](void* ptr) throw() { nlib_free(ptr); }
void* operator new[](size_t size, const std::nothrow_t&) throw() { return nlib_malloc(size); }
#endif
#else
#endif
// Now std::allocator calls nmalloc/nfree.
typedef std::vector<int> MyVec;
static bool vector_pushback() {
MyVec vec;
for (int i = 0; i < 10000; ++i) {
vec.push_back(i);
if (i == 5000) {
// You can dump the current status of the heap in XML.
nlib_printf("#\n# heap status: i == 5000\n#\n");
// Note that it shows the cached memory allocated.
// You have to return the memory to the central heap,
// or set NMALLOC_HEAPOPTION_CACHE_DISABLE to heap_option.
nmalloc_query(NMALLOC_QUERY_CLEAR_CACHE);
nmalloc_query(NMALLOC_QUERY_DUMP, NMALLOC_DUMP_ALL, 1);
}
}
// Verifies here
for (int i = 0; i < 10000; ++i) {
if (vec[i] != i) return false;
}
// Dump again.
nlib_printf("#\n# heap status: i == 10000\n#\n");
nmalloc_query(NMALLOC_QUERY_CLEAR_CACHE);
nmalloc_query(NMALLOC_QUERY_DUMP, NMALLOC_DUMP_ALL, 1);
// vec.clear() and Dumps again.
vec.clear();
nlib_printf("#\n# heap status: vec.clear()\n#\n");
nmalloc_query(NMALLOC_QUERY_CLEAR_CACHE);
nmalloc_query(NMALLOC_QUERY_DUMP, NMALLOC_DUMP_ALL, 1); // the vector is free, but memory is not freed.
// vec.clear() does not free the memory for the vector.
MyVec(vec).swap(vec);
nlib_printf("#\n# heap status: fitting\n#\n");
nmalloc_query(NMALLOC_QUERY_CLEAR_CACHE);
nmalloc_query(NMALLOC_QUERY_DUMP, NMALLOC_DUMP_ALL, 1); // memory is freed...
return true;
}
static bool vector_pushback_with_reserve() {
MyVec vec;
vec.reserve(10000);
for (int i = 0; i < 10000; ++i) {
vec.push_back(i);
}
// Verifies here
for (int i = 0; i < 10000; ++i) {
if (vec[i] != i) return false;
}
nlib_printf("#\n# heap status: i == 10000(with reserve)\n#\n");
nmalloc_query(NMALLOC_QUERY_CLEAR_CACHE);
nmalloc_query(NMALLOC_QUERY_DUMP, NMALLOC_DUMP_ALL, 1); // fragmentation could be avoided.
return true;
}
#ifdef NLIB_HAS_VIRTUALMEMORY
extern "C" void nmalloc_get_settings(NMallocSettings* settings) {
settings->addr = NULL;
settings->size = 1024 * 512;
settings->heap_option = 0;
}
#else
const size_t heapmem_size = 1024 * 512;
NLIB_ALIGNAS(4096) static char heapmem[heapmem_size];
extern "C" void nmalloc_get_settings(NMallocSettings* settings) {
settings->addr = heapmem;
settings->size = heapmem_size;
settings->heap_option = 0;
}
#endif
static bool SampleMain(int, char**) {
return vector_pushback() && vector_pushback_with_reserve();
}
NLIB_MAINFUNC