Very little overhead required for managing memory: only 2 bytes (fixed) + 2 bits per memory block. Those bits are stored within the same managed memory area from which it allocates memory to the client (as opposed to being dynamically allocated).

Fully configurable memory block size (down to 1 byte). The larger the block size, the less overhead (in percent) it needs to reserve for its management.

Provided it is initialized with alignment in mind, it can guaranty that memory it "allocates" is properly aligned. See the docs for whalloc_bt_init() for details. (Note that not all platforms care about alignment (e.g. x86).)

Optionally supports a logging callback function (if not built with NDEBUG defined), allowing the client to trace exactly what memory goes to which allocations. This useful for debuggering and for getting an insight into how the allocator works.

Its main misfeatures are:

De/re/allocation of more than a single block has a linear component. Reallocation, in particular, may have multiple N's in its O(N) (as it has to scan for free blocks when growing).

Each allocator instance can manage, at most, 2^(WHALLOC_BITNESS) memory, and no single allocation can be larger than 2^(WHALLOC_BITNESS-1). The reason is a side effect of how the managed memory addresses are hashed (but to be honest i've forgotten the specifics).