Skip to content

Fixed Memory Allocator

A C++ class implementing a page-chained memory allocator (Alloc, CAlloc, ReAlloc, Free) over a single fixed-size virtual memory block.

Published Jul 14, 1996

CFixedMemory is the in-memory sibling of the file-mapped allocator: instead of mapping a file it reserves one large VirtualAlloc block and runs the same first-fit, page-chain allocation strategy over it. Multi-page allocations are linked as chains with per-page attribute flags (USED, STARTOFCHAIN, ENDOFCHAIN, MANAGER), so ReAlloc can extend a chain in place when the following pages happen to be free, or relocate the data otherwise.

Use it when you want a self-contained heap inside your own process - for example an arena that survives library unload/reload, a sandboxed buffer pool, or just to study how a simple paging allocator works end to end. The Test() method exhausts the pool with uniform and non-uniform sizes, frees everything, then writes and re-reads every byte to verify integrity.

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
	Memory mapping & handing routines.
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define MEMORY_DEFAULT_PAGE_SIZE		128ul //Memory allocation granularity.
#define MEMORY_PAGE_ATTRIB_USED			0x1u  //Pages that are allocated.
#define MEMORY_PAGE_ATTRIB_STARTOFCHAIN	0x2u  //Pages that are allocated.
#define MEMORY_PAGE_ATTRIB_ENDOFCHAIN	0x4u  //Pages that are the tail of a "chain" of pages.
#define MEMORY_PAGE_ATTRIB_MANAGER		0x8u  //Pages that are used by the memory manager itsself.

typedef struct _tag_Memory_Manager_Info {
	unsigned char *uAttribs; //Array of page attributes.
	size_t uUsed;			 //The number of pages that have been allocated (count of non-free pages).
	size_t uCount;			 //The total number of memory manager pages (([Total Mamory] - [Kernel Reserved]) / [Allocation Granularity]).
	size_t uManagerPages;	 //The number of pages reserved my the memory manager for its internal use.
	size_t uSize;			 //Number of bytes in each page.
	size_t uBaseAddress;	 //The base address for all allocations.
} MEMORYMANAGERPAGES, *LPMEMORYMANAGERPAGES;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class CFixedMemory {
public:
	void *CAlloc(size_t uBytes);
	void *CAlloc(size_t uElementCount, size_t uElementSize);
	void *Alloc(size_t uBytes);
	void *Alloc(size_t uElementCount, size_t uElementSize);
	void *ReAlloc(void *pAddress, size_t uTotalBytes);
	bool Free(void *pAddress);
	int FreeAll(void);

	CFixedMemory();
	CFixedMemory(size_t uiTotalRam);
	CFixedMemory(size_t uiTotalRam, size_t uiPageSize);
	~CFixedMemory();

	bool Initialize(size_t uiTotalRam);
	bool Initialize(size_t uiTotalRam, size_t uiPageSize);
	void Destroy();

	void GetPageInfo(MEMORYMANAGERPAGES *pMMP);
	bool Test(void);

	MEMORYMANAGERPAGES *Pages;

private:
	void *AllocP(size_t uBytes, unsigned char uAttributes);
	void *AllocP(size_t uElementCount, size_t uElementSize, unsigned char uAttributes);
	void *ReAllocP(void *pAddress, size_t uTotalBytes, unsigned char uAttributes);

	void *pBaseMemAddress;		//Base of system memory.
};

The driver is minimal - reserve ten megabytes, run the built-in test, done:

#include <Windows.h>
#include <STDIO.h>
#include <STDLIB.h>

#include "CFixedMemory.H"

int main(int argc, char *argv[])
{
	CFixedMemory mem;

	mem.Initialize(1024 * 1024 * 10);

	mem.Test();

	return 0;
}

The implementation mirrors the file-mapped variant almost line for line: Initialize lays the MEMORYMANAGERPAGES structure at the front of the block, reserves enough pages for the per-page attribute array, and marks them MANAGER; AllocP scans forward counting contiguous free pages until it finds enough, flags the run with STARTOFCHAIN/ENDOFCHAIN, and returns the pointer; Free walks to the end of the chain clearing flags; ReAllocP extends in place or allocates-copies-frees. See the File Mapped Memory Allocator article for those bodies in full - only the backing store differs here.

An unhandled error has occurred. Reload 🗙