How-To: Size and Prewarm a Pool

Goal: choose a capacity from measurement rather than guesswork, and remove the first-use spawn cost.

Prerequisites
Quick Start finished, with at least one class actually being pooled.

1. Measure before you choose

Play the heaviest case you care about - the busiest fight, the largest volley - then run Crimson.ObjectPool.Dump and read highWater. That is the most instances that were ever live at once, and it is the number to size against.

Verify
highWater should be stable across repeats of the same scenario. If it climbs every run, instances are not being released.

2. Set the capacity

Project Settings > Crimson > Crimson Object Pool. Default Capacity covers every class; add a Class Overrides entry for anything that differs - a projectile might want 64 while a boss totem wants 2.

Project Settings > Crimson > Crimson Object Pool. Class Overrides sets capacity, growth policy and prewarm count per actor class.
SettingMeaning
CapacityHow many free instances are retained. Not a limit on how many can be live, unless the policy is HardCap.
Growth PolicyGrow spawns past capacity when the free list is empty. HardCap returns null instead.
Prewarm CountInstances spawned and parked when the world begins play. 0 disables it.
Destroy On Over Capacity ReleaseDestroy a released instance when the free list is already full, instead of growing past capacity.
Grow is the safe default
Under Grow, an undersized pool degrades to ordinary spawning - slower, never broken. Under HardCap, Acquire Actor returns null and your code must handle that. Only choose HardCap when a missing actor is genuinely better than an extra one.

3. Prewarm

Set Prewarm Count in a Class Overrides entry to have the pool fill itself automatically shortly after the world begins play. To prewarm from code instead, call it from BeginPlay or later.

Event BeginPlay -> Get Crimson Object Pool Subsystem -> Prewarm Pool (Actor Class, Count).

Never prewarm before the world has begun play
Actors spawned that early have their BeginPlay deferred, and it then runs while they are parked in the free list, undoing their deactivation. The pool refuses the call with a warning rather than letting that happen. BeginPlay or later is always safe.
Verify
Run Crimson.ObjectPool.Dump immediately after starting play. pooled should already equal your prewarm count, and created should not rise during the first burst.

4. Spawn in bulk without a hitch

Acquire Actor is immediate. Asking for fifty actors in a loop spawns fifty in one frame the first time round, before the pool is warm - which is exactly the hitch pooling was supposed to remove. Request Actor Queued spreads the spawning across frames instead and hands each one back through On Pooled Actor Ready.

ForEachLoop (spawn points) -> Request Actor Queued (returns immediately). Then bind Event On Pooled Actor Ready on the subsystem and configure each actor as it arrives. Check the Actor pin for null - a hard-capped pool that ran out reports back with none.

Only real spawns are throttled
Handing back an already-pooled actor is a pop and a reactivation - there is no SpawnActor and nothing to hitch on - so it does not spend the frame budget. A prewarmed pool answers an entire wave in one frame, and the budget only starts to bite once the free list runs dry. Turn off Batch Pooled Acquires if you would rather rate-limit every acquire equally.
Verify
Queue a large wave with the pool cold and watch the frame time - it should stay flat while actors trickle in. Prewarm the same pool and queue the wave again: it should now arrive in a single frame, because nothing needs spawning.

See also

  • How-To: Diagnose Pool Problems
  • API Reference