Program Listing for File main.cpp#

Return to documentation for file (main.cpp)

#include <Windows.h>

#include "MemorySystem.h"

#include <assert.h>
#include <algorithm>
#include <vector>

#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif // _DEBUG

bool MemorySystem_UnitTest();

int main(int i_arg, char**)
{
    const size_t        sizeHeap = 1024 * 1024;

    // you may not need this if you don't use a descriptor pool
    const unsigned int  numDescriptors = 2048;

    // Allocate memory for my test heap.
    void* pHeapMemory = HeapAlloc(GetProcessHeap(), 0, sizeHeap);
    assert(pHeapMemory);

    // Create your HeapManager and FixedSizeAllocators.
    InitializeMemorySystem(pHeapMemory, sizeHeap, numDescriptors);

    bool success = MemorySystem_UnitTest();
    assert(success);

    // Clean up your Memory System (HeapManager and FixedSizeAllocators)
    DestroyMemorySystem();

    HeapFree(GetProcessHeap(), 0, pHeapMemory);

    // in a Debug build make sure we didn't leak any memory.
#if defined(_DEBUG)
    _CrtDumpMemoryLeaks();
#endif // _DEBUG

    return 0;
}

bool MemorySystem_UnitTest()
{
    const size_t maxAllocations = 10 * 1024;
    std::vector<void*> AllocatedAddresses;

    long    numAllocs = 0;
    long    numFrees = 0;
    long    numCollects = 0;

    size_t totalAllocated = 0;

    // reserve space in AllocatedAddresses for the maximum number of allocation attempts
    // prevents new returning null when std::vector expands the underlying array
    AllocatedAddresses.reserve(10 * 1024);

    // allocate memory of random sizes up to 1024 bytes from the heap manager
    // until it runs out of memory
    do
    {
        const size_t        maxTestAllocationSize = 1024;

        size_t          sizeAlloc = 1 + (rand() & (maxTestAllocationSize - 1));

        void* pPtr = malloc(sizeAlloc);

        // if allocation failed see if garbage collecting will create a large enough block
        if (pPtr == nullptr)
        {
            Collect();

            pPtr = malloc(sizeAlloc);

            // if not we're done. go on to cleanup phase of test
            if (pPtr == nullptr)
                break;
        }

        AllocatedAddresses.push_back(pPtr);
        numAllocs++;

        totalAllocated += sizeAlloc;

        // randomly free and/or garbage collect during allocation phase
        const unsigned int freeAboutEvery = 0x07;
        const unsigned int garbageCollectAboutEvery = 0x07;

        if (!AllocatedAddresses.empty() && ((rand() % freeAboutEvery) == 0))
        {
            void* pPtrToFree = AllocatedAddresses.back();
            AllocatedAddresses.pop_back();

            free(pPtrToFree);
            numFrees++;
        }
        else if ((rand() % garbageCollectAboutEvery) == 0)
        {
            Collect();

            numCollects++;
        }

    } while (numAllocs < maxAllocations);

    // now free those blocks in a random order
    if (!AllocatedAddresses.empty())
    {
        // randomize the addresses
        std::random_shuffle(AllocatedAddresses.begin(), AllocatedAddresses.end());

        // return them back to the heap manager
        while (!AllocatedAddresses.empty())
        {
            void* pPtrToFree = AllocatedAddresses.back();
            AllocatedAddresses.pop_back();

            delete[] pPtrToFree;
        }

        // do garbage collection
        Collect();
        // our heap should be one single block, all the memory it started with

        // do a large test allocation to see if garbage collection worked
        void* pPtr = malloc(totalAllocated / 2);

        if (pPtr)
        {
            free(pPtr);
        }
        else
        {
            // something failed
            return false;
        }
    }
    else
    {
        return false;
    }

    // this new [] / delete [] pair should run through your allocator
    char* pNewTest = new char[1024];

    delete[] pNewTest;

    // we succeeded
    return true;
}