{"id":18240665,"url":"https://github.com/endurodave/c_allocator","last_synced_at":"2026-03-03T04:07:35.306Z","repository":{"id":113549526,"uuid":"162932891","full_name":"endurodave/C_Allocator","owner":"endurodave","description":"Fixed Block Memory Allocator in C","archived":false,"fork":false,"pushed_at":"2025-02-18T16:08:31.000Z","size":50,"stargazers_count":20,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-20T07:51:35.620Z","etag":null,"topics":["c-language","cross-platform","embedded-c","malloc-free","memory-allocator"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/endurodave.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-12-24T00:13:53.000Z","updated_at":"2025-03-03T06:13:24.000Z","dependencies_parsed_at":null,"dependency_job_id":"4832e4c2-f9f1-4c0a-baea-6535440818d0","html_url":"https://github.com/endurodave/C_Allocator","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FC_Allocator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FC_Allocator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FC_Allocator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FC_Allocator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/endurodave","download_url":"https://codeload.github.com/endurodave/C_Allocator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247152857,"owners_count":20892564,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c-language","cross-platform","embedded-c","malloc-free","memory-allocator"],"created_at":"2024-11-05T05:04:15.052Z","updated_at":"2026-03-03T04:07:35.288Z","avatar_url":"https://github.com/endurodave.png","language":"C","readme":"![License MIT](https://img.shields.io/github/license/BehaviorTree/BehaviorTree.CPP?color=blue)\n[![conan Ubuntu](https://github.com/endurodave/C_Allocator/actions/workflows/cmake_ubuntu.yml/badge.svg)](https://github.com/endurodave/C_Allocator/actions/workflows/cmake_ubuntu.yml)\n[![conan Ubuntu](https://github.com/endurodave/C_Allocator/actions/workflows/cmake_clang.yml/badge.svg)](https://github.com/endurodave/C_Allocator/actions/workflows/cmake_clang.yml)\n[![conan Windows](https://github.com/endurodave/C_Allocator/actions/workflows/cmake_windows.yml/badge.svg)](https://github.com/endurodave/C_Allocator/actions/workflows/cmake_windows.yml)\n\n# A Fixed Block Memory Allocator in C\n\nA C language fixed block memory allocator improve performance and protect against heap fragmentation faults on any C or C++ project.\n\nSee \u003ca href=\"https://github.com/endurodave/Allocator\"\u003eAn Efficient C++ Fixed Block Memory Allocator\u003c/a\u003e for a C++ version of this allocator. \n\n# Table of Contents\n\n- [A Fixed Block Memory Allocator in C](#a-fixed-block-memory-allocator-in-c)\n- [Table of Contents](#table-of-contents)\n- [Preface](#preface)\n- [Getting Started](#getting-started)\n- [Introduction](#introduction)\n- [Background](#background)\n- [C Language Allocators](#c-language-allocators)\n  - [fb\\_allocator](#fb_allocator)\n  - [x\\_allocator](#x_allocator)\n  - [my\\_allocator](#my_allocator)\n- [Implementation Details](#implementation-details)\n  - [fb\\_allocator Free-List](#fb_allocator-free-list)\n  - [fb\\_allocator Memory Alignment](#fb_allocator-memory-alignment)\n  - [x\\_allocator Meta Data](#x_allocator-meta-data)\n- [Benchmarking](#benchmarking)\n- [Thread Safety](#thread-safety)\n- [Reference Articles](#reference-articles)\n- [Conclusion](#conclusion)\n\n# Preface \n\nOriginally published on CodeProject at: \u003ca href=\"https://www.codeproject.com/Articles/1272619/A-Fixed-Block-Memory-Allocator-in-C\"\u003e\u003cstrong\u003eA Fixed Block Memory Allocator in C\u003c/strong\u003e\u003c/a\u003e\n\n# Getting Started\n\n[CMake](https://cmake.org/) is used to create the project build files on any Windows or Linux machine. The allocator  source code works on any C/C++ compiler on any platform.\n\n1. Clone the repository.\n2. From the repository root, run the following CMake command:   \n   `cmake -B Build .`\n3. Build and run the project within the `Build` directory. \n\n# Introduction\n\n\u003cp\u003eIn 1998, I wrote an article on fixed block memory allocators for Embedded Systems Programming magazine. I received $750 for the piece. Now, articles are written for free on websites such as CodeProject. Oh, how times keep a-changin\u0026rsquo;.\u003c/p\u003e\n\n\u003cp\u003eOne thing that hasn\u0026rsquo;t changed is the usefulness of fixed block allocators. It\u0026rsquo;s a no-no using the global heap on some devices. Throughout my career, I\u0026rsquo;ve written numerous fixed block memory allocators to provide high-speed dynamic-like allocation in memory constrained systems. A generic, well-designed fixed block allocator opens up application implementation possibilities by offering dynamic memory allocations in systems where heap usage is forbidden.\u003c/p\u003e\n\n\u003cp\u003eI\u0026rsquo;ve documented various C++ allocator implementations (see the Reference Articles section). This time, I\u0026rsquo;ll present a C language version with unique features suitable for embedded devices or otherwise.\u003c/p\u003e\n\n\u003cp\u003eThe solution presented here will:\u003c/p\u003e\n\n\u003cul\u003e\n\t\u003cli\u003eBe faster than the global heap\u003c/li\u003e\n\t\u003cli\u003eBe easy to use\u003c/li\u003e\n\t\u003cli\u003eBe thread safe\u003c/li\u003e\n\t\u003cli\u003eSupport fixed block versions of malloc, free, realloc and calloc\u003c/li\u003e\n\t\u003cli\u003eUse minimal code space\u003c/li\u003e\n\t\u003cli\u003eExecute in fixed time\u003c/li\u003e\n\t\u003cli\u003eEliminate heap fragmentation memory faults\u003c/li\u003e\n\t\u003cli\u003eRequire no additional storage overhead (except for a few bytes of static memory)\u003c/li\u003e\n\t\u003cli\u003eHandle memory alignment\u003c/li\u003e\n\t\u003cli\u003eAutomatically dispense variable block size based on demand (a la malloc)\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eTwo simple C modules that dispense and reclaim memory will provide all of the aforementioned benefits, as I\u0026#39;ll show.\u003c/p\u003e\n\n# Background\n\n\u003cp\u003eCustom fixed block memory allocators are used to solve at least two types of memory related problems. First, global heap allocations/deallocations can be slow and nondeterministic. You never know how long the memory manager is going to take. Secondly, to eliminate the possibility of a memory allocation fault caused by a fragmented heap \u0026ndash; a valid concern, especially on mission-critical type systems.\u003c/p\u003e\n\n\u003cp\u003eEven if the system isn\u0026#39;t considered mission-critical, some embedded systems are designed to run for weeks or years without a reboot. Depending on allocation patterns and heap implementation, long-term heap use can lead to heap faults.\u003c/p\u003e\n\n# C Language Allocators\n\n## fb_allocator\n\n\u003cp\u003eEach \u003ccode\u003efb_allocator\u003c/code\u003e instance handles a single block size. The interface is shown below:\u003c/p\u003e\n\n\u003cpre lang=\"C++\"\u003e\nvoid ALLOC_Init(void);\nvoid ALLOC_Term(void);\nvoid* ALLOC_Alloc(ALLOC_HANDLE hAlloc, size_t size);\nvoid* ALLOC_Calloc(ALLOC_HANDLE hAlloc, size_t num, size_t size);\nvoid ALLOC_Free(ALLOC_HANDLE hAlloc, void* pBlock);\u003c/pre\u003e\n\n\u003cp\u003e\u003ccode\u003eALLOC_Init()\u003c/code\u003e is called one time at startup and \u003ccode\u003eALLOC_Term()\u003c/code\u003e at shutdown. Each of the remaining APIs operate in the same manner as the CRT counterparts; \u003ccode\u003eALLOC_Alloc()\u003c/code\u003e allocates memory and \u003ccode\u003eALLOC_Free() \u003c/code\u003edeallocates.\u003c/p\u003e\n\n\u003cp\u003eAn \u003ccode\u003efb_allocator\u003c/code\u003e instance is created using the \u003ccode\u003eALLOC_DEFINE\u003c/code\u003e macro at file scope. The \u003ccode\u003eTestAlloc \u003c/code\u003eallocator below defines a fixed block allocator with a maximum of five 16-byte blocks.\u003c/p\u003e\n\n\u003cpre lang=\"C++\"\u003e\nALLOC_DEFINE(TestAlloc, 16, 5);\u003c/pre\u003e\n\n\u003cp\u003eAllocating a 16-byte block is simple.\u003c/p\u003e\n\n\u003cpre lang=\"C++\"\u003e\nvoid* data = ALLOC_Alloc(TestAlloc, 16);\u003c/pre\u003e\n\n\u003cp\u003eDeallocate the block when done.\u003c/p\u003e\n\n\u003cpre lang=\"C++\"\u003e\nALLOC_Free(TestAlloc, data);\u003c/pre\u003e\n\n## x_allocator\n\n\u003cp\u003eThe \u003ccode\u003ex_allocator\u003c/code\u003e module handles multiple memory block sizes using two or more \u003ccode\u003efb_allocator\u003c/code\u003e instances; one \u003ccode\u003efb_allocator\u003c/code\u003e per block size. During allocation, \u003ccode\u003ex_allocator\u003c/code\u003e returns a block sized from one of the \u003ccode\u003efb_allocator\u003c/code\u003e instances based on the caller\u0026rsquo;s requested size. The \u003ccode\u003ex_allocator\u003c/code\u003e API is shown below:\u003c/p\u003e\n\n\u003cpre lang=\"C++\"\u003e\nvoid* XALLOC_Alloc(XAllocData* self, size_t size);\nvoid XALLOC_Free(void* ptr);\nvoid* XALLOC_Realloc(XAllocData* self, void *ptr, size_t new_size);\nvoid* XALLOC_Calloc(XAllocData* self, size_t num, size_t size);\u003c/pre\u003e\n\n\u003cp\u003eUsers of \u003ccode\u003ex_allocator\u003c/code\u003e typically create a thin wrapper module that (a) defines two or more \u003ccode\u003efb_allocator\u003c/code\u003e instances and (b) provides a custom API to access the \u003ccode\u003ex_allocator\u003c/code\u003e memory. It\u0026rsquo;s easier to explain with a simple example.\u003c/p\u003e\n\n## my_allocator\n\n\u003cp\u003eLet\u0026rsquo;s say we want a fixed block allocator to dispense two block sizes: 32 and 128. We\u0026rsquo;ll call it \u003ccode\u003emy_allocator\u003c/code\u003e and the API is shown below:\u003c/p\u003e\n\n\u003cpre lang=\"C++\"\u003e\nvoid* MYALLOC_Alloc(size_t size);\nvoid MYALLOC_Free(void* ptr);\nvoid* MYALLOC_Realloc(void *ptr, size_t new_size);\nvoid* MYALLOC_Calloc(size_t num, size_t size);\u003c/pre\u003e\n\n\u003cp\u003eThe implementation creates multiple \u003ccode\u003efb_allocator\u003c/code\u003e instances; one to handle each desired block size. In this case, we\u0026rsquo;ll allow at most ten 32-byte blocks and five 128-byte blocks.\u003c/p\u003e\n\n\u003cpre lang=\"C++\"\u003e\n#include \u0026quot;my_allocator.h\u0026quot;\n#include \u0026quot;x_allocator.h\u0026quot;\n\n// Maximum number of blocks for each size\n#define MAX_32_BLOCKS   10\n#define MAX_128_BLOCKS  5\n\n// Define size of each block including meta data overhead\n#define BLOCK_32_SIZE     32 + XALLOC_BLOCK_META_DATA_SIZE\n#define BLOCK_128_SIZE    128 + XALLOC_BLOCK_META_DATA_SIZE\n\n// Define individual fb_allocators\nALLOC_DEFINE(myDataAllocator32, BLOCK_32_SIZE, MAX_32_BLOCKS)\nALLOC_DEFINE(myDataAllocator128, BLOCK_128_SIZE, MAX_128_BLOCKS)\n\n// An array of allocators sorted by smallest block first\nstatic ALLOC_Allocator* allocators[] = {\n    \u0026amp;myDataAllocator32Obj,\n    \u0026amp;myDataAllocator128Obj\n};\n\n#define MAX_ALLOCATORS   (sizeof(allocators) / sizeof(allocators[0]))\n\nstatic XAllocData self = { allocators, MAX_ALLOCATORS };\u003c/pre\u003e\n\n\u003cp\u003eNow, simple one line wrapper functions provide access to the underlying \u003ccode\u003ex_allocator\u003c/code\u003e module.\u003c/p\u003e\n\n\u003cpre lang=\"C++\"\u003e\nvoid* MYALLOC_Alloc(size_t size)\n{\n    return XALLOC_Alloc(\u0026amp;self, size);\n}\n\nvoid MYALLOC_Free(void* ptr)\n{\n    XALLOC_Free(ptr);\n}\n\nvoid* MYALLOC_Realloc(void *ptr, size_t new_size)\n{\n    return XALLOC_Realloc(\u0026amp;self, ptr, new_size);\n}\n\nvoid* MYALLOC_Calloc(size_t num, size_t size)\n{\n    return XALLOC_Calloc(\u0026amp;self, num, size);\n}\u003c/pre\u003e\n\n\u003cp\u003eWhen the caller calls \u003ccode\u003eMYALLOC_Alloc()\u003c/code\u003e with a size between 1 to 32, a 32-byte block is returned. If the requested size is between 33 and 128, a 128-byte block is provided. \u003ccode\u003eMYALLOC_Free()\u003c/code\u003e returns the block to the originating \u003ccode\u003efb_allocator\u003c/code\u003e instance. In this way, a collection of fixed block memory allocators are grouped together providing variable sized memory blocks at runtime based on application demand. The sample wrapper pattern is used again and again offering groups of memory blocks for specific purposes within the system.\u003c/p\u003e\n\n# Implementation Details\n\n\u003cp\u003eMost of the allocator implementation is relatively straight forward. However, I\u0026rsquo;ll explain a few details to assist with key concepts.\u003c/p\u003e\n\n## fb_allocator Free-List\n\n\u003cp\u003eThis is a handy technique for linking blocks together in the free-list without consuming any extra storage for the pointers. After the user calls \u003ccode\u003eALLOC_Free()\u003c/code\u003e, a fixed memory block is no longer being utilized and is freed to be used for other things, like a next pointer. Since the \u003ccode\u003efb_allocator\u003c/code\u003e module needs to keep the deleted blocks around, we put the list\u0026#39;s next pointer in that currently unused block space. When the block is reused by the application, the pointer is no longer needed and will be overwritten by the user object. This way, there is no per-instance storage overhead incurred linking blocks together.\u003c/p\u003e\n\n\u003cp\u003eThe free-list is actually implemented as a singly linked list, but the code only adds/removes from the head so the behavior is that of a stack. Using a stack makes the allocation/deallocations really fast and deterministic. No loop searching for a free block \u0026ndash; just push or pop a block and go.\u003c/p\u003e\n\n\u003cp\u003eUsing freed object space as the memory to link blocks together means the object must be large enough to hold a pointer. The \u003ccode\u003eALLOC_BLOCK_SIZE \u003c/code\u003emacro ensures that the minimum size is met.\u003c/p\u003e\n\n## fb_allocator Memory Alignment\n\n\u003cp\u003eSome embedded systems require memory to be aligned on a particular byte boundary. Since the allocator\u0026rsquo;s memory is a contiguous \u003ccode\u003estatic\u003c/code\u003e byte array, having blocks start on an unaligned boundary could cause a hardware exception on some CPUs. For instance, 13-byte blocks will cause a problem if 4-byte alignment is required. Change \u003ccode\u003eALLOC_MEM_ALIGN \u003c/code\u003eto the byte boundary desired. The block size will be rounded up to the next nearest aligned boundary.\u003c/p\u003e\n\n## x_allocator Meta Data\n\n\u003cp\u003eThe \u003ccode\u003ex_allocator\u003c/code\u003e implementation adds 4-bytes of meta data per block. For instance, if 32-byte blocks are required by the user, the \u003ccode\u003ex_allocator\u003c/code\u003e actually uses 36-byte blocks. The extra 4-bytes are used to hide an \u003ccode\u003efb_allocator\u003c/code\u003e pointer inside the block (assuming the pointer is 4-bytes in size).\u003c/p\u003e\n\n\u003cp\u003eWhen deleting memory, \u003ccode\u003ex_allocator\u003c/code\u003e needs the original \u003ccode\u003efb_allocator\u003c/code\u003e instance so the deallocation request can be routed to the correct \u003ccode\u003efb_allocator\u003c/code\u003e instance for processing. Unlike \u003ccode\u003eXALLOC_Alloc()\u003c/code\u003e, \u003ccode\u003eXALLOC_Free()\u003c/code\u003e does not take a size and only uses a \u003ccode\u003evoid*\u003c/code\u003e argument. Therefore, \u003ccode\u003eXALLOC_Alloc()\u003c/code\u003e actually hides a pointer to the \u003ccode\u003efb_allocator\u003c/code\u003e within an unused portion of the memory block by adding an additional 4-bytes to the request. The caller gets a pointer to the block\u0026rsquo;s client region where the hidden \u003ccode\u003efb_allocator\u003c/code\u003e pointer is not overwritten.\u003c/p\u003e\n\n\u003cpre lang=\"C++\"\u003e\nvoid* XALLOC_Alloc(XAllocData* self, size_t size)\n{\n    ALLOC_Allocator* pAllocator;\n    void* pBlockMemory = NULL;\n    void* pClientMemory = NULL;\n\n    ASSERT_TRUE(self);\n\n    // Get an allocator instance to handle the memory request\n    pAllocator = XALLOC_GetAllocator(self, size);\n\n    // An allocator found to handle memory request?\n    if (pAllocator)\n    {\n        // Get a fixed memory block from the allocator instance\n        pBlockMemory = ALLOC_Alloc(pAllocator, size + XALLOC_BLOCK_META_DATA_SIZE);\n        if (pBlockMemory)\n        {\n            // Set the block ALLOC_Allocator* ptr within the raw memory block region\n            pClientMemory = XALLOC_PutAllocatorPtrInBlock(pBlockMemory, pAllocator);\n        }\n    }\n    else\n    {\n        // Too large a memory block requested\n        ASSERT();\n    }\n\n    return pClientMemory;\n} \u003c/pre\u003e\n\n\u003cp\u003eWhen \u003ccode\u003eXALLOC_Free()\u003c/code\u003e is called, the allocator pointer is extracted from the memory block so the correct \u003ccode\u003efb_allocator\u003c/code\u003e instance can be called to deallocate the block.\u003c/p\u003e\n\n\u003cpre lang=\"C++\"\u003e\nvoid XALLOC_Free(void* ptr)\n{\n    ALLOC_Allocator* pAllocator = NULL;\n    void* pBlock = NULL;\n\n    if (!ptr)\n        return;\n\n    // Extract the original allocator instance from the caller\u0026#39;s block pointer\n    pAllocator = XALLOC_GetAllocatorPtrFromBlock(ptr);\n    if (pAllocator)\n    {\n        // Convert the client pointer into the original raw block pointer\n        pBlock = XALLOC_GetBlockPtr(ptr);\n\n        // Deallocate the fixed memory block\n        ALLOC_Free(pAllocator, pBlock);\n    }\n}\u003c/pre\u003e\n\n# Benchmarking\n\n\u003cp\u003eBenchmarking the allocator performance vs. the global heap on a Windows PC shows just how fast the code\u0026nbsp;is. A\u0026nbsp;basic test of allocating and deallocating 20000 4096 and 2048 sized blocks in a somewhat interleaved fashion\u0026nbsp;tests the speed improvement. See the attached source code for the exact algorithm.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003e\u003cstrong\u003eWindows Allocation Times in Milliseconds\u003c/strong\u003e\u003c/p\u003e\n\n\u003ctable class=\"ArticleTable\"\u003e\n\t\u003cthead\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003eAllocator\u003c/td\u003e\n\t\t\t\u003ctd\u003eMode\u003c/td\u003e\n\t\t\t\u003ctd\u003eRun\u003c/td\u003e\n\t\t\t\u003ctd\u003eBenchmark Time (mS)\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003eGlobal Heap\u003c/td\u003e\n\t\t\t\u003ctd\u003eRelease\u003c/td\u003e\n\t\t\t\u003ctd\u003e1\u003c/td\u003e\n\t\t\t\u003ctd\u003e36.3\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003eGlobal Heap\u003c/td\u003e\n\t\t\t\u003ctd\u003eRelease\u0026nbsp;\u003c/td\u003e\n\t\t\t\u003ctd\u003e2\u003c/td\u003e\n\t\t\t\u003ctd\u003e33.8\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003eGlobal Heap\u003c/td\u003e\n\t\t\t\u003ctd\u003eRelease\u0026nbsp;\u003c/td\u003e\n\t\t\t\u003ctd\u003e3\u003c/td\u003e\n\t\t\t\u003ctd\u003e32.8\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003efb_allocator\u003c/td\u003e\n\t\t\t\u003ctd\u003eStatic Pool\u003c/td\u003e\n\t\t\t\u003ctd\u003e1\u003c/td\u003e\n\t\t\t\u003ctd\u003e22.6\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003efb_allocator\u003c/td\u003e\n\t\t\t\u003ctd\u003eStatic Pool\u003c/td\u003e\n\t\t\t\u003ctd\u003e2\u003c/td\u003e\n\t\t\t\u003ctd\u003e3.7\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003efb_allocator\u003c/td\u003e\n\t\t\t\u003ctd\u003eStatic Pool\u003c/td\u003e\n\t\t\t\u003ctd\u003e3\u003c/td\u003e\n\t\t\t\u003ctd\u003e4.9\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003ex_allocator\u003c/td\u003e\n\t\t\t\u003ctd\u003eStatic Pool\u003c/td\u003e\n\t\t\t\u003ctd\u003e1\u003c/td\u003e\n\t\t\t\u003ctd\u003e33.9\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003ex_allocator\u003c/td\u003e\n\t\t\t\u003ctd\u003eStatic Pool\u003c/td\u003e\n\t\t\t\u003ctd\u003e2\u003c/td\u003e\n\t\t\t\u003ctd\u003e6.9\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003ex_allocator\u003c/td\u003e\n\t\t\t\u003ctd\u003eStatic Pool\u003c/td\u003e\n\t\t\t\u003ctd\u003e3\u003c/td\u003e\n\t\t\t\u003ctd\u003e7.7\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003cp\u003eWindows uses a debug heap when executing within the debugger. The debug heap adds extra safety checks slowing its performance. The release heap is much faster as the checks are disabled. The debug heap can be disabled within\u0026nbsp;Visual Studio by setting\u0026nbsp;\u003cstrong\u003e_NO_DEBUG_HEAP=1\u003c/strong\u003e in the \u003cstrong\u003eDebugging \u0026gt; Environment\u0026nbsp;\u003c/strong\u003eproject option.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eThis benchmark\u0026nbsp;test is very simplistic and a more realistic scenario with varying blocks sizes and random new/delete intervals might produce different results. However, the basic point is illustrated nicely; the memory manager is slower than allocator and highly dependent on the platform\u0026#39;s implementation.\u003c/p\u003e\n\n\u003cp\u003eThe \u003ccode\u003efb_allocator \u003c/code\u003euses a static memory pool and doesn\u0026#39;t rely upon the heap. This has a fast\u0026nbsp;execution time of around 4mS once the free-list is populated with blocks. The 22.6mS on fb_allocator Run 1\u0026nbsp;accounts for dicing up the fixed memory pool into individual blocks on the first run.\u003c/p\u003e\n\n\u003cp\u003eThe \u003ccode\u003ex_allocator \u003c/code\u003eused within the bm_allocator module is a bit slower at ~7mS since it has overhead to allocate/deallocate\u0026nbsp;mutiple sized blocks wherease \u003ccode\u003efb_allocator\u003c/code\u003e only supports one block size.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eIn comparison to the Windows global heap, the \u003ccode\u003efb_allocator \u003c/code\u003eis about 8 times faster and \u003ccode\u003ex_allocator \u003c/code\u003eis about 5 times faster. On embedded devices, I\u0026#39;ve seen as high as a 15x speed increase over the global heap.\u0026nbsp;\u003c/p\u003e\n\n# Thread Safety\n\n\u003cp\u003eThe \u003ccode\u003eLK_LOCK \u003c/code\u003eand \u003ccode\u003eLK_UNLOCK \u003c/code\u003emacros within the \u003ccode\u003eLockGuard\u003c/code\u003e module implement the software locks needed for thread safety. Update the lock implementation as required for your platforms operating system.\u003c/p\u003e\n\n# Reference Articles\n\n\u003cul\u003e\n\t\u003cli\u003e\u003ca href=\"https://github.com/endurodave/Allocator\"\u003eAn Efficient C++ Fixed Block Memory Allocator\u003c/a\u003e - by David Lafreniere\u003c/li\u003e\n\t\u003cli\u003e\u003ca href=\"https://github.com/endurodave/xallocator\"\u003eReplace malloc/free with a Fast Fixed Block Memory Allocator\u003c/a\u003e - by David Lafreniere\u003c/li\u003e\n\t\u003cli\u003e\u003ca href=\"https://github.com/endurodave/stl_allocator\"\u003eA Custom STL std::allocator Replacement Improves Performance\u003c/a\u003e - by David Lafreniere\u003c/li\u003e\n\u003c/ul\u003e\n\n# Conclusion\n\n\u003cp\u003eThe C-based fixed block memory allocator presented here is suitable for any C or C++ system. For a C++ specific implementation with its own unique features, see the referenced articles.\u003c/p\u003e\n\n\u003cp\u003eUse the \u003ccode\u003efb_allocator\u003c/code\u003e whenever you need to allocate a single block size. Use \u003ccode\u003ex_allocator\u003c/code\u003e when dispensing multiple block sizes is desired. Create multiple \u003ccode\u003ex_allocator\u003c/code\u003e wrappers to segregate memory pools depending on intended usage.\u003c/p\u003e\n\n\u003cp\u003eIf you have an application that really hammers the heap and is causing slow performance, or if you\u0026rsquo;re worried about a fragmented heap fault, integrating \u003ccode\u003efb_allocator\u003c/code\u003e and \u003ccode\u003ex_allocator\u003c/code\u003e may help solve those problems. The implementation was kept to a minimum facilitating use on even the smallest of embedded systems.\u003c/p\u003e\n\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fendurodave%2Fc_allocator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fendurodave%2Fc_allocator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fendurodave%2Fc_allocator/lists"}