Table of Contents

PoolFactory Class

Builds ObjectPool<T> instances, including for types this package does not reference.

Namespace

CryptoHives.Foundation.Memory.Pools

Syntax

public static class PoolFactory

Overview

Where ObjectPools offers ready-made rent helpers for a handful of common types, PoolFactory is the layer beneath: it creates the pools, and exposes a general-purpose CreatePool<T> for anything else.

Methods

CreatePool

public static ObjectPool<T> CreatePool<T>(
    Func<T> create,
    Func<T, bool> reset,
    int maximumRetained = 0) where T : class;

Creates a pool for any reference type from a pair of delegates.

Parameter Description
create Produces a new instance when the pool is empty
reset Restores an instance on return. Return true to keep it, false to reject it.
maximumRetained Maximum instances to keep. Zero or less uses the default, which scales with the processor count.

Throws ArgumentNullException when either delegate is null.

Warning

A rejected instance is dropped, not disposed. When reset returns false the pool simply lets the instance go. If T holds unmanaged or pooled resources, reset must dispose it before returning false, or those resources are never released.

CreateBufferWriterPool

public static ObjectPool<ArrayPoolBufferWriter<T>> CreateBufferWriterPool<T>(int maximumRetained = 0);

Creates a pool of ArrayPoolBufferWriter<T> instances.

The pool takes no writer settings: those are applied when a writer is rented, so instances in the pool are interchangeable. Hand the returned pool to an ArrayPoolBufferWriterProvider<T> to rent from it.

Most callers do not need this — SharedBufferWriterPool<T>() is what every provider uses by default, and sharing it is the point. Create a separate pool only to isolate a use case deliberately.

SharedBufferWriterPool

public static ObjectPool<ArrayPoolBufferWriter<T>> SharedBufferWriterPool<T>();

The shared pool for T, one per element type.

CreateStringBuilderPool

public static ObjectPool<StringBuilder> CreateStringBuilderPool(
    int maxCapacity = DefaultStringBuilderCapacity,
    int maxStringBuilderCapacity = DefaultMaxStringBuilderCapacity);

SharedStringBuilderPool

public static ObjectPool<StringBuilder> SharedStringBuilderPool { get; }

The pool behind ObjectPools.GetStringBuilder().

Constants

Constant Value Description
DefaultStringBuilderCapacity 1024 Maximum number of builders a pool retains
DefaultMaxStringBuilderCapacity 8192 Ceiling on how large a builder may be and still be worth pooling
InitialStringBuilderCapacity 128 Capacity, in characters, that a fresh pooled builder starts with
Note

No pool built here is released under memory pressure. DefaultObjectPool<T> drops an instance only when its policy rejects one or the pool is full on return, so a filled pool stays filled for the life of the process. Rented arrays are different — ArrayPool<T>.Shared trims itself on every gen-2 collection.

Usage

Pooling a type from another library

CreatePool exists so callers can pool types the Memory package deliberately does not reference. Utf8JsonWriter is the motivating case: it is poolable — a sealed class with Reset overloads — but System.Text.Json is a package dependency on this library's older targets, so Memory stays clear of it.

ObjectPool<Utf8JsonWriter> pool = PoolFactory.CreatePool(
    create: () => new Utf8JsonWriter(Stream.Null),
    reset:  writer => { writer.Reset(Stream.Null); return true; });

Utf8JsonWriter json = pool.Get();
try
{
    using var buffer = ObjectPools.RentBufferWriter<byte>();
    json.Reset(buffer);

    json.WriteStartObject();
    json.WriteString("name", "cryptohives");
    json.WriteEndObject();
    json.Flush();

    using SequenceLease<byte> payload = buffer.LeaseSequence();
    Send(payload.Sequence);
}
finally
{
    pool.Return(json);
}

Note that Utf8JsonReader cannot be pooled at all — it is a ref struct, so it is stack-only and cannot be stored in a field. It needs no pooling either: it allocates nothing on the heap.

Rejecting an instance that must not be reused

ObjectPool<Session> pool = PoolFactory.CreatePool(
    create: () => new Session(),
    reset:  session =>
    {
        if (session.IsFaulted)
        {
            session.Dispose();   // the pool will not do this for you
            return false;
        }

        session.Clear();
        return true;
    });

Pairing a pool with an object owner

ObjectPool<MyClass> pool = PoolFactory.CreatePool(
    () => new MyClass(),
    obj => { obj.Clear(); return true; });

using var owner = new ObjectOwner<MyClass>(pool);
MyClass obj = owner.PooledObject;

Thread Safety

Thread-safe. The pools returned are safe for concurrent use; the instances they hand out generally are not.

See Also


© 2026 The Keepers of the CryptoHives