User Guide

This document provides a brief description of the PPMalloc modules and then provides some basic information on using these modules. You will want to consult documentation for individual modules for more detailed information about them.

PPMalloc Modules

Module
Description Source
Dependencies
GeneralAllocator
Implements a general purpose allocator. EAGeneralAllocator.h/cpp
EABase
GeneralAllocatorDebug
Implements a user-level debug layer on top of GeneralAllocator. Useful for doing named allocations, recording stack traces, doing delayed frees, etc. EAGeneralAllocatorDebug.h/cpp
EAGeneralAllocatorDebugPS2.cpp,
EAGeneralAllocatorDebugWin32.cpp, etc.
GeneralAllocator
SystemAllocator
StackAllocator
Implements a fast allocator that works by incrementing a pointer through a block of memory. EAStackAllocator.h/cpp
EABase
FixedAllocator
Implements a pool of same-sized objects, for fast allocation and tight object packing and good similar-object locality. EAFixedAllocator.h/cpp
EABase
NonLocalAllocator
Implements an allocator for memory that is inaccessable by the entity allocating it. EANonLocalAllocator.h/cpp
GeneralAllocator
SmallObjectAllocator
Implements an allocator specialized for non-fragmenting small-sized blocks EASmallObjectAllocator.h/cpp
EABase
SmallBlockAllocator Alternative to SmallObjectAllocator. extras/EASmallObjectAllocator.h/cpp EABase
ScratchpadAllocator Implements a per-thread stack allocator for fast temporary per-thread memory. More flexible than alloca, similar to C99 dynamically sized automatic arrays but portable and more flexible.    
HandleAllocator
Implements a handle-based allocator with conventional lock semantics and heap compaction. Useful for preventing heap fragmentation problems. EAHandleAllocator.h/cpp
GeneralAllocator
SystemAllocator
Implements an allocator which uses the underlying operating system or kernel libraries for memory allocation. Useful for implementing underneath custom allocators such as those here. EASystemAllocator.h
EABase
AllocationRecorder
Implements an automated allocation activity recording and playback system for any generalized allocator, such as GeneralAllocator. Useful for doing offline testing of memory allocation patterns and behaviour. EAAllocationRecorder.h/cpp
EABase
AllocatorInterface
Implements the EA IAllocator interface on top of GeneralAllocator. EAAllocatorInterface.h/cpp
GeneralAllocator
GeneralAllocatorDebug
NewDelete
Implements overrides for the C++ new and delete operators.
EANewDelete/cpp EABase
GeneralAllocatorSTL
Defines a custom STL allocator which uses GeneralAllocator as the allocation source.
EAGeneralAllocatorSTL.h GeneralAllocator

The Basics

Most likely, what you are primarily interested in is GeneralAllocator. The other modules provide more esoteric functionality that you may want to consider for advanced systems. Either way, GeneralAllocator stands by itself has has no dependencies on the other modules; you can just grab GeneralAllocator.h/cpp and throw the rest away if that suits your needs.

All code is in C++ and largely follows the EA coding guidelines as of January of 2004. All classes are in the EA::Allocator C++ namespace. Thus, the fully qualified name of GeneralAllocator is EA::Allocator::GeneralAllocator. Most of the code is plain C++ and doesn't attempt to be very academic with the language. Thus RTTI is not used, template usage is used only in one module (FixedAllocator), exception handling is not used, etc. Unit tests have been set up for most of the functionality and are available with the full package. The headers are heavily commented in Doxygen-savvy format and the source code for the primary modules has been heavily commented as well.

GeneralAllocator Examples

Here we provide some basic examples showing how to use GeneralAllocator.

#include "PPMalloc/EAGeneralAllocator.h"
using namespace EA::Allocator;

GeneralAllocator allocator;
void* p = allocator.Malloc(20);
allocator.Free(p);

To use GeneralAllocatorDebug, you simply substitute that class for GeneralAllocator, like this:

#include "PPMalloc/EAGeneralAllocatorDebug.h"
using namespace EA::Allocator;
 
GeneralAllocatorDebug allocator;
void* p = allocator.Malloc(20);
allocator.Free(p);

If you want to initialize the allocator with a large block of existing memory, you simply pass that memory into the constructor or Init function, like so:

GeneralAllocator allocator(pMemory, nMemorySize);

If you would like to use GeneralAllocatorDebug to allocate memory with a name attached to it, you would do this:

allocator.MallocDebug(20, 0, "model");

If you would like to use GeneralAllocatorDebug to allocate memory which tracks the full call stack and the allocation time along with a name, you would do this:

unsigned flags = (1 << GeneralAllocatorDebug::kDebugDataIdCallStack) || 
                 (1 << GeneralAllocatorDebug::kDebugDataIdAllocationTime);
allocator.MallocDebug(20, flags, "model");

If you would like to validate the heap to see if there has been any corruption, you would do this:

allocator.ValidateHeap(GeneralAllocator::kHeapValidationLevelFull);

If you would like to provide a C++ hook function to track all allocation activity, you would use SetHookFunction like this:

void SomeClass::SetupHook()
{
    allocator.SetHookFunction(HookFunction, this);
}

static void HookFunction(const GeneralAllocator::HookInfo* pHI, void* pContext)
{
    SomeClass* const pSomeClass = (SomeClass*)pContext; // Possibly use this.
     
    if(!pHookInfo->mbEntry) // If we are being called at the end of the function (so we can see the result)...
    {
        if(pHookInfo->mHookType == GeneralAllocator::kHookTypeMalloc)
           pHookInfo->mnSizeInputTotal, pHookInfo->mpDataOutput;
        else if(pHookInfo->mHookType == GeneralAllocator::kHookTypeFree)
           pHookInfo->mpDataInput;
    }
}

If you would like to use GeneralAllocator as a sub heap of some other heap (e.g. another GeneralAllocator), you would simply do this:

GeneralAllocator gaParent;
GeneralAllocator gaChild(gParent.Malloc(1000000), 1000000, false);      

If you want to have a sub heap that grows on demaind, you would do this:

size_t SubHeapCoreFreeFunction(GeneralAllocator* /*pChild*/, void* pCore, size_t nSize, void* pContext)
{
    GeneralAllocator* const pParent = (GeneralAllocator*)pContext;
    pParent->Free(pCore);
    return nSize;
}
     
bool MallocFailureFunction(GeneralAllocator* pChild, size_t nSize, void* pContext)
{
    GeneralAllocator* const pParent = (GeneralAllocator*)pContext;
    if(nSize < 1000000) // Allocate at least N bytes of new core.
       nSize = 1000000;
    void* const pNewCore = pParent->Malloc(nSize);
    if(pNewCore)
       pChild->AddCore(pNewCore, nSize, true, false, SubHeapCoreFreeFunction, pParent);
    return (pNewCore != NULL);
}
     
// Create a main heap.
GeneralAllocator gaParent;
     
// Create a sub heap from the main heap.
GeneralAllocator gaChild(gaParent.Malloc(1000000), 1000000, false, false, SubHeapCoreFreeFunction, &gaParent);
gaChild.SetMallocFailureFunction(MallocFailureFunction, &gaParent);
gaChild.SetOption(GeneralAllocator::kOptionEnableSystemAlloc, 0);


End of document