Writing a simple pool allocator in C

Allocator design & implementation choices

  • Several commenters note that fixed-size pool allocators are common (e.g., in RTOSes, embedded code, and personal libraries).
  • Questions arise about why the Pool struct (just a couple of pointers) is heap-allocated at all, and why two separate malloc() calls are used instead of co-allocating control structure and chunks.
  • Some argue co-allocation reduces fragmentation and improves performance; others say it complicates an educational example, especially if targeting C89 without flexible array members.
  • Alignment is a recurring concern: aligning chunk sizes, ensuring space for an internal pointer in free-list nodes, and potentially using C11 features like _Alignas(max_align_t).

Free-list structure & performance

  • One participant criticizes linked lists for allocator bookkeeping, favoring trees or bitsets for cache locality and asymptotic complexity.
  • Others respond that this particular pool allocator never searches; it only pushes/pops from the head, so operations are O(1), making a simple singly linked free list appropriate.
  • Distinction is made between “free list” as an old term of art and the more precise idea that this usage is effectively a stack.

Safety, tooling, and debugging

  • Suggestions include adding: thread safety, variable-sized allocations, automatic zeroing, double-free detection, and better error checking.
  • Multiple comments recommend integrating with Valgrind and AddressSanitizer via their APIs (including manual poisoning/redzones) so that custom allocators still benefit from modern debugging tools.
  • Some embedded and GC examples are mentioned where cooperating with these tools avoids false positives.

Strict aliasing, C object model, and UB

  • A long subthread debates whether such allocators violate C’s strict-aliasing and effective-type rules.
  • Views range from “allocators inevitably break the model, so the model is broken” to “type-changing stores into allocated storage are explicitly allowed in C, if done carefully.”
  • There is disagreement over whether malloc() itself can be written in strictly conforming C, touching on pointer provenance, out-of-bounds pointers, and hardware features like memory tagging.
  • Some projects simply disable strict aliasing (-fno-strict-aliasing) in practice.

API design & ergonomics

  • Several commenters propose:
    • Making chunk size a per-pool parameter (one pool per object type).
    • Hiding pool_expand() and number-of-chunks; auto-expand inside pool_alloc().
    • Lazy initialization on first allocation instead of allocating in pool_new().
    • Treating the pool like a stack with an operation to free everything back to a saved “index”.

Benchmarking & real-world use

  • The article’s claim that pools are “much faster than malloc” is challenged; commenters insist on concrete benchmarks and realistic workloads.
  • Detailed advice is shared on how to design, run, and interpret allocator benchmarks, including controlling environment, varying workloads, and using profiling tools.
  • It’s noted that specialized allocators can win big for specific load profiles, but the system allocator comes with built-in debugging and security checks that custom allocators risk losing.