FTA:
“Of course you can build C memory allocators that avoid or amortize this overhead, mostly obviously by having free() never do anything (some programs will be perfectly fine with this and it's very fast)”I also don’t see how that bookkeeping would be necessary for allocated memory. For example, make you minimal allocation large enough to keep a (pointer, size) pair, keep a linked list of free blocks, each with their size, implement first fit malloc, splitting of any remaining parts, and have free chain up freed blocks to the end of that list. Not a good allocator (it could fragment memory badly, for example), but it would work.
It also would break horribly if the program passed incorrect pointers or sizes to free, but that would be the program’s problem. malloc isn’t required to protect against buggy programs.