Concurrent with this is the need to replace the system allocator on Win32 with TnFOX's one which typically yields a 6x speed increase for multithreaded C++ programs. A unified system is required for all this as there is only one global new and delete operator. It is rather important that you read and understand the following discussion.
Due to how C++ (and C) works, there is one global new
and delete
operator which supposedly can be wholly replaced by any program according to the standard. This isn't actually true - on Win32, you can only replace per binary (DLL or EXE) and on GNU/ELF/POSIX your operator replacements get happily overrided by any shared objects loaded after your binary. It gets worse - when working with containers or any code which speculatively allocates memory (eg; buffering), a container can quickly come to consist of blocks allocated from a multitude of memory pools all at once leaving us with no choice other than to permit any thread with any memory pool currently set to be able to free any other allocation, no matter where it was allocated. Furthermore, we must also tolerate other parts of the C library or STL allocating with the default allocator and freeing using ours (GCC is particularly bad for this when optimisation is turned on).
It was for all these reasons that getting the custom memory allocation infrastructure working took a week or so of testing. I tried a number of schemes and eventually came down with one which is reasonably fast but does cost an extra four bytes per allocation within a non-global memory pool. You the user must also observe some caveats:
new
and delete
operators where those operators do not use directly malloc()
and free()
. Both MSVC and GCC are fine here. new
and delete
operators. If you try, you will get a compile error as an inlined version is defined anywhere a TnFOX header file is included. std::set_new_handler()
.There are some defines which affect how the custom memory allocation system works:
FXDISABLE_SEPARATE_POOLS when
defined to 1 forces exclusive use of the system allocator by the global allocator replacements (directly using FXMemoryPool still uses the special heap). Note that this comes with a twelve byte book-keeping overhead (24 bytes on 64 bit architectures) on every allocation and is intended only for debugging purposes (especially memory leak checking). If undefined, is 1 in debug mode and 0 in release mode. FXDISABLE_GLOBAL_MARKER when
defined to 1 does not place a marker in each non-pool specific allocation (thus saving four bytes or eight bytes on 64 bit architectures). While this saves memory, it does mean that the allocator replacements can no longer detect when they are freeing memory allocated by the system allocator and thus invoke that instead - therefore the onus is on you to ensure that if you receive a block allocated from say within another library, it is up to you to call free()
on it rather than free()
. If undefined, is 1 on both Win32 and POSIX.
Classes | |
class | FX::FXMemoryPool |
A threadsafe custom memory pool. More... | |
Functions | |
template<typename T> | |
FXMALLOCATTR T * | FX::malloc (size_t size, FXMemoryPool *heap=0) throw () |
template<typename T> | |
FXMALLOCATTR T * | FX::calloc (size_t no, size_t size, FXMemoryPool *heap=0) throw () |
template<typename T> | |
FXMALLOCATTR T * | FX::realloc (T *p, size_t size, FXMemoryPool *heap=0) throw () |
template<typename T> | |
void | FX::free (T *p, FXMemoryPool *heap=0) throw () |
FXMALLOCATTR char * | FX::strdup (const char *str) throw () |
FXDLLPUBLIC FXMALLOCATTR void * | operator new (size_t size) throw (std::bad_alloc) |
FXDLLPUBLIC FXMALLOCATTR void * | operator new[] (size_t size) throw (std::bad_alloc) |
FXDLLPUBLIC void | operator delete (void *p) throw () |
FXDLLPUBLIC void | operator delete[] (void *p) throw () |
FXDLLPUBLIC FXMALLOCATTR void * | operator new (size_t size, FX::FXMemoryPool *heap) throw (std::bad_alloc) |
FXDLLPUBLIC FXMALLOCATTR void * | operator new[] (size_t size, FX::FXMemoryPool *heap) throw (std::bad_alloc) |
FXDLLPUBLIC void | operator delete (void *p, FX::FXMemoryPool *heap) throw () |
FXDLLPUBLIC void | operator delete[] (void *p, FX::FXMemoryPool *heap) throw () |
FXAPI FXMALLOCATTR void * | FX::realloc (void *p, size_t size, FXMemoryPool *heap=0) throw () |
FXAPI void | FX::free (void *p, FXMemoryPool *heap=0) throw () |
FXAPI void | FX::failonfree (void *p, FXMemoryPool *heap=0) throw () |
FXAPI void | FX::unfailonfree (void *p, FXMemoryPool *heap=0) throw () |
FXAPI FXMALLOCATTR void * | tnfxmalloc (size_t size) |
FXAPI FXMALLOCATTR void * | tnfxcalloc (size_t no, size_t size) |
FXAPI FXMALLOCATTR void * | tnfxrealloc (void *p, size_t size) |
FXAPI void | tnfxfree (void *p) |
FXAPI FXMALLOCATTR void * FX::malloc | ( | size_t | size, | |
FXMemoryPool * | heap = 0 | |||
) | throw () [inline] |
FXAPI FXMALLOCATTR void * FX::calloc | ( | size_t | no, | |
size_t | size, | |||
FXMemoryPool * | heap = 0 | |||
) | throw () [inline] |
T * FX::realloc | ( | T * | p, | |
size_t | size, | |||
FXMemoryPool * | heap = 0 | |||
) | throw () [inline] |
Resizes memory
References FX::realloc().
void FX::free | ( | T * | p, | |
FXMemoryPool * | heap = 0 | |||
) | throw () [inline] |
Frees memory
References FX::Secure::free().
char * FX::strdup | ( | const char * | str | ) | throw () [inline] |
Duplicates a string
References FX::Secure::malloc().
FXDLLPUBLIC void * operator new | ( | size_t | size | ) | throw (std::bad_alloc) [inline] |
Global operator new replacement
References FX::Secure::malloc().
FXDLLPUBLIC void * operator new[] | ( | size_t | size | ) | throw (std::bad_alloc) [inline] |
Global operator new replacement
References FX::Secure::malloc().
FXDLLPUBLIC void operator delete | ( | void * | p | ) | throw () [inline] |
Global operator delete replacement
References FX::Secure::free().
FXDLLPUBLIC void operator delete[] | ( | void * | p | ) | throw () [inline] |
Global operator delete replacement
References FX::Secure::free().
FXDLLPUBLIC void * operator new | ( | size_t | size, | |
FX::FXMemoryPool * | heap | |||
) | throw (std::bad_alloc) [inline] |
operator new with a specific pool
References FX::Secure::malloc().
FXDLLPUBLIC void * operator new[] | ( | size_t | size, | |
FX::FXMemoryPool * | heap | |||
) | throw (std::bad_alloc) [inline] |
operator new with a specific pool
References FX::Secure::malloc().
FXDLLPUBLIC void operator delete | ( | void * | p, | |
FX::FXMemoryPool * | heap | |||
) | throw () [inline] |
operator delete with a specific pool
References FX::Secure::free().
FXDLLPUBLIC void operator delete[] | ( | void * | p, | |
FX::FXMemoryPool * | heap | |||
) | throw () [inline] |
operator delete with a specific pool
References FX::Secure::free().
FXAPI FXMALLOCATTR void* FX::realloc | ( | void * | p, | |
size_t | size, | |||
FXMemoryPool * | heap = 0 | |||
) | throw () |
Resizes memory
Referenced by FX::realloc().
FXAPI void FX::free | ( | void * | p, | |
FXMemoryPool * | heap = 0 | |||
) | throw () |
Frees memory
FXAPI void FX::failonfree | ( | void * | p, | |
FXMemoryPool * | heap = 0 | |||
) | throw () |
Causes an assertion failure when the specified memory block is freed
FXAPI void FX::unfailonfree | ( | void * | p, | |
FXMemoryPool * | heap = 0 | |||
) | throw () |
Removes a previous FX::failonfree()
FXAPI FXMALLOCATTR void* tnfxmalloc | ( | size_t | size | ) |
Allocates memory
FXAPI FXMALLOCATTR void* tnfxcalloc | ( | size_t | no, | |
size_t | size | |||
) |
Allocates memory
FXAPI FXMALLOCATTR void* tnfxrealloc | ( | void * | p, | |
size_t | size | |||
) |
Resizes memory
FXAPI void tnfxfree | ( | void * | p | ) |
Frees memory