Skip to content

Core.Utilities.ResourcePool

Dennis Steffen edited this page Jan 4, 2026 · 1 revision

The file ResourcePool<T>.cs implements the Object Pool Pattern. This is a design pattern used to manage a cache of objects that can be reused, rather than creating and destroying them repeatedly. This is particularly useful in game development (like in gui service for lists) to reduce Garbage Collection (GC) pressure and improve performance.

Detailed Explanation

  1. Core Purpose: It manages a collection of objects of type T. Instead of calling new T() every time you need an object, you "Rent" one from the pool. When you are done, you "Return" it.
  2. Key Components:
    • _itemsReady (Queue): Stores objects that are currently available for use.
    • _itemsInUse (List): Keeps track of objects currently rented out.
    • _createItem (Func): A factory method used to instantiate new objects when the pool is empty or being initialized.
    • _resetItem (Action): A crucial callback that "cleans" an object before it is reused (e.g., resetting health to 100, clearing a list, or zeroing a position).
    • _autoSize: If true, the pool will create new objects on the fly if it runs out. If false, it will throw an exception, which is useful for strictly limiting memory usage.
  3. Lifecycle Methods:
    • Rent(): Pulls an object from the queue. if the queue is empty and autoSize is enabled, it creates a new one.
    • Return(T item): Resets the item using the provided action and moves it from the "in-use" list back to the "ready" queue.
    • ReleaseAll(): Forces all active objects back into the pool.
    • Dispose(): Clears the pool and, importantly, checks if the objects themselves implement IDisposable to call their cleanup logic.

Use Cases

  1. Game Projectiles: In a shooter, bullets are created and destroyed rapidly. Using a pool prevents thousands of allocations per minute.
  2. VFX/Particles: Short-lived visual effects like sparks or smoke clouds.
  3. UI Elements: In a scrollable list with hundreds of items, you might only pool the 10-20 visible "cell" objects.
  4. Network Buffers: Reusing byte arrays for sending/receiving packets to avoid memory fragmentation.

Examples

Example 1: Managing "Bullets" in a Game

In this scenario, we create a pool for a Bullet class. When a bullet is returned, we reset its Active state and Velocity.

public class Bullet 
{
    public Vector2 Position;
    public Vector2 Velocity;
    public bool IsActive;
}

// Initialization
var bulletPool = new ResourcePool<Bullet>(
    initialPoolSize: 20,
    autoSize: true,
    createItem: () => new Bullet(),
    resetItem: bullet => 
    {
        bullet.IsActive = false;
        bullet.Position = Vector2.Zero;
        bullet.Velocity = Vector2.Zero;
    }
);

// Usage
var myBullet = bulletPool.Rent();
myBullet.IsActive = true;
myBullet.Position = new Vector2(100, 100);

// Later, when the bullet hits a wall:
bulletPool.Return(myBullet);

Example 2: Reusing Data Buffers (Memory Management)

If you are processing data frequently, you can pool List<int> objects to avoid allocating new lists.

var listPool = new ResourcePool<List<int>>(
    initialPoolSize: 5,
    autoSize: true,
    createItem: () => new List<int>(1024), // Pre-allocate capacity
    resetItem: list => list.Clear()        // Clear the list so it's ready for new data
);

// Usage
var heavyList = listPool.Rent();
heavyList.Add(42);

// Use the list...

// Return to pool instead of letting GC handle it
listPool.Return(heavyList);

**Pro-Tip **

Since this class implements IDisposable, you should ideally use it with a using statement if its lifetime is scoped to a specific method, or ensure the parent class containing the pool also implements IDisposable to clean up the resources properly when the engine shuts down.

Clone this wiki locally