#include <FXMemoryPool.h>
One of the things I've always wanted in my programming library but haven't had since my RISC-OS days is the ability to create arbitrary heaps (called memory pools nowadays as some idiot called a variant of an ordered tree programming pattern a "heap"). RISC-OS made custom heaps very easy as you just called SWI OS_HeapCreate
and even today it has the unique property of letting you create one wherever you like. Sadly we couldn't offer this here.
But why would you want to have lots of custom heaps around the place? Because put simply, it can increase performance and reduce memory usage, never mind allowing some isolation of memory corruption and making it easy to prevent memory overuse attacks by malicious parties. Despite the many advantages of using custom heaps, they are very rarely used despite C++ offering per-class allocators. This is a shame, but understandable given you must do slightly more work to make full use of them.
Given there's a lack of documentation on why they're useful, I'll outline it here. Performance increases can be gained especially when allocating lots of small simple objects - you can skip the destruction completely for the entire set by allocating from a custom heap, then simply deleting the heap rather than destroying each individually. Memory usage can be reduced because heaps fragment - the C++ freestore is particularly notorious for this and any algorithm with good performance tends to waste lots of memory in unallocated portions. Thus if you can reduce the fragmentation, you can substantially reduce the working set of your application. Finally, memory corruption can be isolated if you can contain some piece of code to work from a custom heap - if it dies horribly, you can be pretty safe with some kinds of code to delete the heap and be sure the corruption won't spread - like cutting out a cancer. Don't over-rely on this however.
As of v0.80 of TnFOX, FXMemoryPool has been substantially augmented from the merging of TMemPool into it from Tn. Furthermore there is now process-wide replacement of all dynamic memory allocation to use this library instead. The default STDC malloc
, calloc
, realloc
and free
have been left available as sometimes a third party library will return a pointer to you which you must later free and using the TnFOX replacements will cause a segfault. There is now a facility for a "current pool" set per thread which causes all global memory allocations to occur from that pool. See FX::FXMemPoolHold.
This particular heap implementation is not my own - previous to v0.86 it used the famous ptmalloc2 which is the standard allocator in GNU glibc (and thus is the standard allocator for Linux). As of v0.86 onwards it uses nedmalloc, an even better memory allocator once again. nedmalloc has a similar design to ptmalloc2 except that it adds a threadcache for improved scalability so the following resources remain useful:
ptmalloc2 was shown to have the optimum speed versus wastefulness of all thread-optimised allocators according to Sun (http://developers.sun.com/solaris/articles/multiproc/multiproc.html). You can read more about how ptmalloc2's algorithm works at http://gee.cs.oswego.edu/dl/html/malloc.html. Note that nedmalloc is compiled in debug mode when TnFOX is compiled as such - thus you may get assertion errors if you corrupt the nedmalloc based heap.
If you'd like to know more in general about heap algorithms, implementations and performance, please see ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps
You are guaranteed that irrespective of which memory pool you allocate from, you can free it with any other memory pool in effect. This is a requirement for any serious usage. When you create a FXMemoryPool, you can supply which thread you wish to associate it with - when that thread exits, the memory pool will automatically be deleted. Deletion of a memory pool can take one of two forms - either immediate, or marked for deletion when the last block allocated within it is freed.
FXMemoryPool keeps some statistics of how many memory pools are in use and how much data has been allocated in each. This can be monitored during testing to ensure that you haven't forgotten to use a memory pool when you should.
TnFOX defines implementations of the ANSI C dynamic memory functions within the FX namespace but it also defines templated versions for easier type casting plus all versions take an optional parameter allowing you to manually specify which heap to use. The global new and delete operator overrides similarly have such an extra (optional) parameter.
Public Member Functions | |
FXMemoryPool (FXuval maximum=(FXuval)-1, const char *identifier=0, QThread *owner=0, bool lazydeleted=false) | |
FXuval | size () const throw () |
FXuval | maxsize () const throw () |
FXMALLOCATTR void * | malloc (FXuval size) throw () |
FXMALLOCATTR void * | calloc (FXuint no, FXuval size) throw () |
void | free (void *blk) throw () |
FXMALLOCATTR void * | realloc (void *blk, FXuval size) throw () |
Static Public Member Functions | |
static FXMemoryPool * | poolFromBlk (void *blk) throw () |
static FXMALLOCATTR void * | glmalloc (FXuval size) throw () |
static FXMALLOCATTR void * | glcalloc (FXuval no, FXuval size) throw () |
static void | glfree (void *blk) throw () |
static FXMALLOCATTR void * | glrealloc (void *blk, FXuval size) throw () |
static bool | gltrim (FXuval left) throw () |
static Statistics | glstats () throw () |
static FXString | glstatsAsString () |
static FXMemoryPool * | current () |
static void | setCurrent (FXMemoryPool *heap) |
static QMemArray< MemoryPoolInfo > | statistics () |
Static Public Attributes | |
static const FXuval | minHeapVirtualSpace |
Friends | |
FXAPI void * | malloc (size_t size, FXMemoryPool *heap) throw () |
FXAPI void * | calloc (size_t no, size_t _size, FXMemoryPool *heap) throw () |
FXAPI void * | realloc (void *p, size_t size, FXMemoryPool *heap) throw () |
FXAPI void | free (void *p, FXMemoryPool *heap) throw () |
Classes | |
struct | MemoryPoolInfo |
Data reflecting a memory pool. More... | |
struct | Statistics |
A structure containing statistics about the pool. More... |
FX::FXMemoryPool::FXMemoryPool | ( | FXuval | maximum = (FXuval)-1 , |
|
const char * | identifier = 0 , |
|||
QThread * | owner = 0 , |
|||
bool | lazydeleted = false | |||
) |
Allocates a pool which can grow to size maximum. Virtual address space is allocated in blocks of FX::FXMemoryPool::minHeapVirtualSpace so you might as well allocate one of those by default. You can also set an identifier (for debugging) and associate the pool with a thread whereby when that thread exits, the pool will be deleted. Setting lazydeleted means the pool doesn't really die after destruction until the last block is freed from it.
FXuval FX::FXMemoryPool::size | ( | ) | const throw () |
Returns the size of the pool.
FXuval FX::FXMemoryPool::maxsize | ( | ) | const throw () |
Returns the maximum size of the pool.
FXMALLOCATTR void* FX::FXMemoryPool::malloc | ( | FXuval | size | ) | throw () |
Allocates a block, returning zero if unable.
FXMALLOCATTR void* FX::FXMemoryPool::calloc | ( | FXuint | no, | |
FXuval | size | |||
) | throw () |
Allocates a zero initialised block, returning zero if unable.
void FX::FXMemoryPool::free | ( | void * | blk | ) | throw () |
Frees a block.
FXMALLOCATTR void* FX::FXMemoryPool::realloc | ( | void * | blk, | |
FXuval | size | |||
) | throw () |
Extends a block, returning zero if unable. Note that like the ANSI realloc()
you must still free blk on failure.
static FXMemoryPool* FX::FXMemoryPool::poolFromBlk | ( | void * | blk | ) | throw () [static] |
Returns the memory pool associated with a memory chunk (=0 if from system pool, =-1 if not from any pool).
static FXMALLOCATTR void* FX::FXMemoryPool::glmalloc | ( | FXuval | size | ) | throw () [static] |
Allocates a block from the global heap, returning zero if unable.
static FXMALLOCATTR void* FX::FXMemoryPool::glcalloc | ( | FXuval | no, | |
FXuval | size | |||
) | throw () [static] |
Allocates zero-filled no of blocks of size size from the global heap, returning zero if unable
static void FX::FXMemoryPool::glfree | ( | void * | blk | ) | throw () [static] |
Frees a block from the global heap.
static FXMALLOCATTR void* FX::FXMemoryPool::glrealloc | ( | void * | blk, | |
FXuval | size | |||
) | throw () [static] |
Extends a block in the global heap, returning zero if unable. Note that like the ANSI realloc()
you must still free blk on failure.
static bool FX::FXMemoryPool::gltrim | ( | FXuval | left | ) | throw () [static] |
Trims the heap down to the minimum possible, releasing memory back to the system.
static Statistics FX::FXMemoryPool::glstats | ( | ) | throw () [static] |
Returns a set of usage statistics about the heap.
static FXString FX::FXMemoryPool::glstatsAsString | ( | ) | [static] |
Returns a set of usage statistics about the heap as a string.
static FXMemoryPool* FX::FXMemoryPool::current | ( | ) | [static] |
Retrieves the memory pool in use by the current thread (=0 for system pool).
static void FX::FXMemoryPool::setCurrent | ( | FXMemoryPool * | heap | ) | [static] |
Sets the memory pool to be used by the current thread (=0 for system pool).
static QMemArray<MemoryPoolInfo> FX::FXMemoryPool::statistics | ( | ) | [static] |
Returns a list of memory pools existing.
FXAPI void* malloc | ( | size_t | size, | |
FXMemoryPool * | heap | |||
) | throw () [friend] |
Allocates memory
Allocates memory
FXAPI void* calloc | ( | size_t | no, | |
size_t | _size, | |||
FXMemoryPool * | heap | |||
) | throw () [friend] |
Allocates memory
Allocates memory
FXAPI void* realloc | ( | void * | p, | |
size_t | size, | |||
FXMemoryPool * | heap | |||
) | throw () [friend] |
Resizes memory
FXAPI void free | ( | void * | p, | |
FXMemoryPool * | heap | |||
) | throw () [friend] |
Frees memory
const FXuval FX::FXMemoryPool::minHeapVirtualSpace [static] |
Defines the size of block virtual address space is allocated in.