exec Memory Pools

Memory pools are exec.library's private, self-tracking memory management scheme, introduced in Kickstart 3.0 (V39). They curb global memory fragmentation, remove most of the need for Forbid()/Permit() locking around allocation, and let an entire allocation group be freed with one call. The API lives in both exec.library (CreatePool, DeletePool, AllocPooled, FreePooled) and amiga.lib (LibCreatePool, LibDeletePool, LibAllocPooled, LibFreePooled).

AmigaOS 3.2 reverted the pool implementation to the V40 puddle-based scheme ("just without the V40 bugs") — see AmigaOS 3.2 — What Changed for Developers. This article explains how that puddle scheme actually works, drawn from Olaf Barthel's developer documentation added in NDK 3.2 R4.

How pools are built: puddles and the threshold

A pool is a private memory management domain that a single Task/Process uses (or that multiple tasks share if access is restricted to one at a time). CreatePool takes three parameters:

APTR CreatePool(ULONG memFlags, ULONG puddleSize, ULONG threshSize);
  • memFlags — a memory-flags specifier as taken by AllocMem.
  • puddleSize — the size of each puddle. Pools are made of fixed-size puddles, all the same size. Many small allocations fit in a single puddle.
  • threshSize — the largest allocation that goes into normal puddles. Must be less than or equal to puddleSize (or CreatePool() fails). Allocations larger than threshSize get their own dedicated puddle.

New puddles are allocated from global shared memory as needed, once an allocation no longer fits the existing puddles. The point is to move fragmentation inside the puddles rather than across the global memory space.

The puddle-size pitfall

Every new puddle is allocated from global shared memory in full, even if you only need a tiny portion of it. If your puddle size is a poor match for your allocation sizes — e.g. so large that only 1-3 allocations fit per puddle — you get large-scale memory fragmentation that ties up far more memory than needed.

Take stock of your allocation pattern first: there are usually few large allocations and many small ones. Pick the puddle size from your largest small allocations and how many are in use over time.

Inspecting a pool: show_memory_pool_insights()

The V39 pool API never shipped a way to query pool performance — total puddle memory, fill ratios, fragment counts. That is still true in AmigaOS 3.2. The R4 DeveloperDocumentation/MemoryPools/memory_pool_insights.h header fills the gap with a diagnostic function:

#define SHOW_MEMORY_POOL_INSIGHTS
#include "memory_pool_insights.h"

show_memory_pool_insights(SysBase, pool);

Omit the #define and it compiles to a no-op macro. Caution: it reads Kickstart 3.x internal pool/puddle data structures and will not work with AmigaOS 4's different pool design.

The output (via kprintf) looks like:

total pool size = 24 (header) + 116480 (puddle size) + 0 (large allocations) bytes -> 116504 bytes
total pool size minus free puddle memory = 106328 bytes
number of puddles = 14
number of large allocations = 0
number of fragments in puddles = 21
puddles memory used = 106304 of 116480 bytes (91%)
memory usage = 100% puddles and 0% large allocations
how many puddles are filled to a specific percentage (no overlaps!):
        > 50% = 1 (4744 bytes -> 4% of all puddle memory)
        > 70% = 3 (19216 bytes -> 16% of all puddle memory)
        > 90% = 10 (82344 bytes -> 70% of all puddle memory)

How to read it:

  • total pool size — header + all puddles + all large allocations. How much global memory the pool reserves.
  • number of puddles — grows over time, rarely shrinks. Allocations made together may land in different puddles and free at different times, stranding puddles nearly empty.
  • number of fragments in puddles — freed small allocations that cannot merge. More fragments forces more puddle creation; keep this low.
  • puddles memory used — should approach total puddle size for good utilisation.
  • memory usage — the puddle-vs-large-allocation split. Too many large allocations means you should adjust puddleSize/threshSize.
  • puddle fill histogram — a good outcome is the 90-100% bucket holding most of the memory.

The original 1992 design intent

The 1992 plan was to keep pool internals opaque so features like virtual memory could be layered in later. That never materialised on 3.x. You should not tinker with the pool data structures at runtime — future versions may change them. A possible future path (as AmigaOS 4 demonstrated) is a proper query API plus an optional arbitration mechanism so multiple tasks can share a pool without extra locking.

See Also


Sources: Olaf Barthel, NDK 3.2 R4 DeveloperDocumentation/MemoryPools (README + memory_pool_insights.h), 2022-01-23. Raw: raw/exec/memory-pools.md Updated: 2026-08-04