Skip to content

Object Pooling

The Object Pooling system in Nalix.Framework provides a thread-safe, high-performance mechanism for recycling expensive class instances, reducing the frequency of garbage collection.

Object Pool Interaction Flow

The following diagram illustrates the lifecycle of a poolable object from creation to reuse.

flowchart LR
    Start[Request Object] --> Cache{Available in Pool?}
    Cache -- Yes --> Get[Retrieve from Storage]
    Cache -- No --> Build[Create new Instance]

    Get --> Use[Use Object]
    Build --> Use

    Use --> Return[Return to Pool]
    Return --> Reset[Reset State IPoolable]
    Reset --> Check{Capacity Full?}

    Check -- No --> Save[Store for Reuse]
    Check -- Yes --> Dispose[Dispose and GC]

Source Mapping

  • src/Nalix.Abstractions/IPoolable.cs
  • src/Nalix.Framework/Memory/Pools/ObjectPool.cs
  • src/Nalix.Framework/Memory/Objects/ObjectPoolManager.cs
  • src/Nalix.Framework/Memory/Objects/TypedObjectPool.cs

IPoolable Interface

Any class intended for pooling must implement IPoolable.

public interface IPoolable
{
    /// <summary>
    /// Resets the object state to its default values before being returned to the pool.
    /// </summary>
    void Reset();
}

State Management

Correctly implementing Reset() is critical. Failure to clear collections or reset properties can lead to "polluted" objects being served in future requests.

ObjectPoolManager

ObjectPoolManager is the central registry for all typed pools. It maintains statistics, performs health checks, and handles background trimming.

Key Features

  • Dynamic Creation: Pools are created lazily for each type as needed.
  • Typed Pools: Provides TypedObjectPool<T> for high-performance, type-safe access.
  • Health Monitoring: Tracks cache hits, misses, and Peak Concurrent Usage.
  • Advanced Diagnostics: Optional deep tracking for object lifetimes (avg/p95/max), outstanding counts, suspicious long-lived objects, and GC leak detection.
  • Trimming: Supports scheduled or manual trimming to release objects back to the GC during low-load periods.

Key API Members

Member Description
Get<T>() Retrieves an item from the pool for type T. Creates a new one if the pool is empty.
Return<T>(obj) Resets and returns an object to the pool.
GetTypedPool<T>() Gets or creates a type-specific TypedObjectPool<T> adapter.
Prealloc<T>(count) Force-fills the pool with a specific number of instances (useful at startup).
SetMaxCapacity<T>(maxCapacity) Sets the maximum capacity for a specific type's pool.
ResetMetrics() Resets all global and per-pool metrics to baseline (zero).
ClearPool<T>() Clears all objects from a specific type's pool.
ClearAllPools() Clears all objects from all pools.
TrimAllPools(percentage = 50) Trims all pools to their target sizes.
ScheduleRegularTrimming(interval, percentage = 50, ct) Schedules a background trimming loop.
PerformHealthCheck() Identifies "unhealthy" pools (those with consistently high miss rates).
ResetStatistics() Resets all statistics for the pool manager and all pools.
GetTypeInfo<T>() Gets detailed information about a specific type's pool.
GenerateReport() Produces a detailed text summary of all managed pools and their metrics.
GetReportData() Returns a structured dictionary for monitoring dashboards.

Properties

Property Type Description
DefaultMaxPoolSize int Default maximum size for new pools (default 1024).
PoolCount int Total number of pools currently managed.
PeakPoolCount int Peak number of pools at any time.
TotalGetOperations long Total number of get operations performed.
TotalReturnOperations long Total number of return operations performed.
TotalCacheHits long Total number of cache hits.
TotalCacheMisses long Total number of cache misses.
CacheHitRate double Overall cache hit rate as a percentage (0-100).
Uptime TimeSpan Uptime of the pool manager.
UnhealthyPoolCount int Number of unhealthy pools.

TypedObjectPool<T>

For performance-critical code, it is recommended to cache a TypedObjectPool<T> rather than calling the manager directly.

// Recommended performance pattern
private readonly TypedObjectPool<MyPacket> _pool = 
    ObjectPoolManager.Instance.GetTypedPool<MyPacket>();

public void Process()
{
    var item = _pool.Get();
    try { /* ... */ }
    finally { _pool.Return(item); }
}

Monitoring and Health

The manager tracks several critical metrics to help tune pool capacities:

  • Hit Rate: The percentage of requests satisfied by the pool without creating a new object.
  • Outstanding: Number of objects currently held by application code (requires EnableDiagnostics).
  • Peak Outstanding: The high-water mark of concurrent objects active at any time (requires EnableDiagnostics).
  • Consecutive Failures: High number of cache misses in sequence, suggesting the pool capacity is too low for the current load.

Advanced Diagnostics

Advanced diagnostics can be enabled via ObjectPoolOptions (usually in default.ini under [ObjectPool]). These features provide deep insight at a slight performance cost.

Statistics Collected

  • Lifetime (Avg/p95/Max): How long objects stay rented. High values might indicate slow processing segments.
  • Suspicious Objects: Objects held longer than a configurable threshold (e.g., 30s) are listed in reports with their allocation stack trace.
  • GC Leak Detection: Uses sentinel finalizers to detect and report objects that were garbage collected without being returned to the pool.

Configuration Example

[ObjectPool]
EnableDiagnostics = true
CaptureStackTraces = true
EnableLeakDetection = true
SuspiciousThresholdSeconds = 30

Diagnostic Insight

Use ScheduleRegularTrimming to keep memory usage balanced. Trimming runs PerformHealthCheck automatically to log warnings about unhealthy pools.