Class Allocator.

The Allocator class does the heavy lifting for Oryx memory allocation system, a simple garbage collector for event-driven servers.

Our GC system is based on the notion of eternal objects and safe GC points. Eternal objects must be declared by calling addEternal. Collectible objects are allocated by calling alloc(), or alternatively by inheriting Garbage. Most Oryx classes inherit Garbage.

The free() function mark all objects that can be reached from the eternal ones, and afterwards frees anything which isn't reachable. It can be called whenever there are no pointers into the heap, ie. only during the main event loop.

Ech single instance of the Allocator class allocates memory blocks of a given size. There are static functions to the heavy loading, such as free() to free all unreachable memory, allocate() to allocate something, allocator() to find an Allocator responsible for a given size and finally rounded(), to find the largest size which will fit comfortably in an allocation block, rounded().

The String and UString classes can call rounded() to optimize their memory usage.

Allocator::Allocator( uint s )

This private constructor creates an Allocator to dispense objects of size at most s - sizeof(void*) bytes.

static void Allocator::addEternal( const void * p, const char * t )

Records that *p is an allocation root, i.e. that whatever it points to is a valid object. t is a description of this root (e.g. "array of connection objects").

void * Allocator::alloc( uint s, uint n )

Allocates s bytes of collectible memory, which may contain up to n pointers. If n is too large to be contained within s bytes, alloc() uses the largest legal value. The default value is UINT_MAX, which in practise means that the entire object may consist of pointers.

Note that s is a uint, not a size_t. In our universe, it isn't possible to allocate more than 4GB at a time. So it is.

void * Allocator::allocate( uint size, uint pointers )

Allocates a chunk of memory (which may contain up to pointers pointers), notes that at most size bytes are in use, and returns a pointer to it.

static uint Allocator::allocated()

Returns the number of bytes allocated since the last memory sweep.

Allocator * Allocator::allocator( uint size )

Returns a pointer to the Allocator responsible for size. size need not be rounded.

void * Allocator::block( uint i )

Returns a pointer to block no. i in this Allocator. The pointer is to the management word, not the payload.

uint Allocator::chunkSize() const

Returns the amount of memory gobbled up when this Allocator allocates memory. This is a little bigger than the biggest object this Allocator can provide.

void Allocator::dealloc( void * p )

Deallocates the object at p.

This is never strictly necessary, however, if a very large number of objects are allocated and deallocated, it may be beneficial. This function exists because it was beneficial in String::reserve().

void Allocator::deallocate( void * p )

Deallocates the object at p, provided that it's within this Allocator. Calling this function is never necessary, since free() does the same job. However, String helps out by doing it occasionally.

static void Allocator::dumpRandomObject()

This debug function selects an allocated memory block at random and dumps its contents to stdout.

Each allocated byte has the same chance of being chosen, so this function has a tendency to pick large objects. (Although, if almost all of the allocated objects are 32-byte objects, this function is almost certain to pick a 32-byte object.)

static void Allocator::free()

Frees all memory that's no longer in use. This can take some time.

static uint Allocator::inUse()

Returns the number of bytes in use after the last sweep.

void Allocator::insert()

This private helper inserts the allocator in the tree used by owner().

static void Allocator::mark( void * p )

This private helper checks that p is a valid pointer to unmarked GCable memory, marks it, and puts it on a stack so that mark() can process it and add its children to the stack.

static void Allocator::mark()

This private helper processes all the stacked pointers, scanning them for valid pointers and marking any that exist.

static Allocator * Allocator::owner( void * p )

Returns a pointer to the Allocator in which p lies, or a null pointer if p doesn't seem to be a valid pointer.

static void Allocator::removeEternal( const void * p )

Records that *p is no longer an allocation root. The object may have been deleted.

static void Allocator::removeEternal( void * p )

Records that *p is no longer an allocation root. The object may have been deleted.

static uint Allocator::rounded( uint size )

Returns the biggest number of bytes which can be allocated at the same effective cost as size.

Suppose allocating 24, 25 or 28 bytes all cause Allocator to use 32 bytes, but 29 causes Allocator to use 48. Then rounded(24), rounded(25) and rounded(28) all return 28, while rounded(29) might return something like 44.

This can be used by String and UString to optimize their memory usage. Perhaps also by other classes.

static void Allocator::scan( void * p )

This debug function prints a summary of the memory usage for p on stdout. It can be conveniently be called using 'call Allocator::scan( p )' from gdb.

static uint Allocator::scan1( void * p, bool print, uint level, uint limit )

Scans the pointer in p and returns its total size, ie. the sum of the sizes of the objects to which it contains. If it contains several pointers to the same object, that object is counted several times.

if print is true and the total cost is ast least limit, scan1() also prints some debug output on stdout, prefixed by level spaces. If print is false, level and limit are ignored.

static void Allocator::scan2( void * p )

Scans the pointer in p and clears all the marked bits left by scan1().

static void Allocator::scanRoots()

Prints the memory usage of the roots.

static void Allocator::setReporting( bool report )

Instructs the Allocator to log various statistics if report is true, and to be entirely silent if report is false.

The initial value is false.

static uint Allocator::sizeOf( void * p )

Returns the amount of memory allocated to hold p and any object to which p points.

The return value can bee an overstatement. For example, if p contains two pointers to the same object, that object is counted twice.

void Allocator::sweep()

Sweeps this allocator, freeing all unmarked memory blocks and unmarking all memory blocks.

Allocator::~Allocator()

Destroys the object and frees its allocated memory.

This web page based on source code belonging to Oryx Mail Systems GmbH. All rights reserved.