In this lesson, you will learn how to stabilize your game's memory footprint by managing long-lived containers to prevent performance-killing fragmentation.
The Fragmentation Problem
When you constantly add elements to a TArray or TMap, the container periodically requests a larger block of memory from the heap. If your game has been running for a while, the available heap space becomes a "patchwork" of small, scattered gaps. Even if you have enough total memory, the system might fail to find a single contiguous block large enough for your growing container, leading to frequent reallocations and slow performance.
Strategies for Stability
To minimize fragmentation, you must move away from "letting the container decide" and start managing capacity manually.
-
Reserve Capacity Early: If you know a container will hold roughly 100 items, don't let it grow organically. Use
Reserve()to allocate the memory upfront. This ensures the memory is claimed in one single, clean block.TArray<FEnemyData> EnemyList; EnemyList.Reserve(128); // Pre-allocate to avoid mid-game reallocations -
Reuse Instead of Recreate: Instead of clearing a container and letting it shrink—which triggers a deallocation—consider keeping the container alive and simply resetting the count. Reusing an existing
TArraymemory block keeps that memory "warm" and avoids returning it to the heap where it might become fragmented. -
Pool Your Data: For objects that are frequently created and destroyed, use an Object Pool. By pre-allocating a fixed number of items at game startup, you avoid the "allocate, grow, deallocate" cycle entirely. When an enemy "dies," return it to the pool instead of destroying it. This keeps your memory layout static and predictable.
Balancing Growth
If you must allow for growth, use a "growth factor" strategy. Doubling the size of a container is efficient for speed, but if your containers are massive, consider a more conservative growth strategy or a TMap with a fixed Reserve() limit. By reducing the frequency of reallocations, you ensure your game remains fluid and avoids the overhead of the memory manager struggling to find space.
Key Takeaway: Prevent memory fragmentation by reserving capacity upfront and reusing existing containers instead of constantly reallocating memory during gameplay.