Skip to main content

dotnext-memory

Allocation-free memory routines from the DotNext and DotNext.Unsafe NuGet packages - SpanOwner (safe stackalloc with pooled fallback), BufferWriterSlim (stack-allocated StringBuilder/buffer replacement with string interpolation), PoolingBufferWriter, PoolingArrayBufferWriter, SparseBufferWriter, and the MemoryAllocator abstraction over ArrayPool, plain arrays and unmanaged memory. Use when reducing allocations in .NET hot paths; when stackalloc length comes from input; when replacing StringBuilder, MemoryStream, RecyclableMemoryStream, ArrayBufferWriter or manual ArrayPool rent/return code; or when making the memory allocation strategy configurable.

Informations de source

Dépôt
dotnet/dotNext
Dernière activité de la source
6 octobre 2026 à 14:10
Langue détectée de SKILL.md
anglais
Étoiles
1 967
Forks
157

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
dotnext-memory
description
Allocation-free memory routines from the DotNext and DotNext.Unsafe NuGet packages - SpanOwner (safe stackalloc with pooled fallback), BufferWriterSlim (stack-allocated StringBuilder/buffer replacement with string interpolation), PoolingBufferWriter, PoolingArrayBufferWriter, SparseBufferWriter, and the MemoryAllocator abstraction over ArrayPool, plain arrays and unmanaged memory. Use when reducing allocations in .NET hot paths; when stackalloc length comes from input; when replacing StringBuilder, MemoryStream, RecyclableMemoryStream, ArrayBufferWriter or manual ArrayPool rent/return code; or when making the memory allocation strategy configurable.
license
MIT
metadata
{"dotnext-version":"6.x"}
# Before you start 1. Check which version of `DotNext` and `DotNext.Unsafe` the project references (`.csproj` or `Directory.Packages.props`). This skill describes 6.x. For older versions, verify each member you use against the XML docs/IntelliSense of the referenced version. 2. The types below are in several namespaces. Add the `using` shown next to each type. 3. If this skill doesn't cover what you need (API details, more examples), find the relevant article in the documentation index: https://dotnet.github.io/dotNext/llms.txt Most of the types are in `DotNext` package. In case of unmanaged memory allocations, add `DotNext.Unsafe` dependency as well. # Use Cases - Avoid **stackalloc** which length is an input from the untrusted source: user input, request parameter, etc. If the length is expected to be small, but you need safe fallback, use `SpanOwner<T>` (`DotNext.Buffers`) data type. - Always declare it with `using`. When the length exceeds the threshold, `SpanOwner<T>` rents the memory from the pool, and `Dispose` returns it. For a stack-allocated span, `Dispose` does nothing. - Choose the threshold in bytes, not elements: divide by `Unsafe.SizeOf<T>()` for other element types. - Canonical example: ```cs using DotNext.Buffers; public static void Encode(ReadOnlySpan<char> input, Stream output, Encoding encoding) { const int stackallocThreshold = 512; // in bytes; keep it small, the stack is limited int maxByteCount = encoding.GetMaxByteCount(input.Length); using SpanOwner<byte> buffer = (uint)maxByteCount <= (uint)stackallocThreshold ? stackalloc byte[maxByteCount] : new SpanOwner<byte>(maxByteCount); var bytesWritten = encoding.GetBytes(input, buffer.Span); output.Write(buffer.Span.Slice(0, bytesWritten)); } ``` - Consider `DotNext.Buffers.BufferWriterSlim<T>` type in combination with extension methods from `DotNext.Buffers.Text.CharBuffer` class instead of `System.Text.StringBuilder` in synchronous code because its initial buffer can be allocated on the stack. If the buffer overflows, the writer uses memory allocator to rent the memory (by default it uses `ArrayPool<T>.Shared`). String interpolation for this type is exposed by the `Interpolate` extension method from `DotNext.Text.StringInterpolation` class. - The initial buffer must have the same element type as the writer: `stackalloc char[...]` for `BufferWriterSlim<char>`. - Keep `Interpolate` outside of the `try` block: calling it on a `BufferWriterSlim<char>` local inside `try`/`finally` fails to compile (CS8347/CS8350), and `using var writer` is not allowed either (CS1657, a `using` variable can't be passed by `ref`). If `Interpolate` throws, the rented buffer is not returned to the pool, which is harmless. - `WrittenSpan` becomes invalid after `Dispose()`. Consume or copy it before. - Canonical example: ```cs using DotNext.Buffers; using DotNext.Text; var writer = new BufferWriterSlim<char>(stackalloc char[256]); writer.Interpolate($"Hello, {name}!"); try { ConsumeWrittenChars(writer.WrittenSpan); } finally { writer.Dispose(); } ``` - Consider `PoolingBufferWriter<T>` (`DotNext.Buffers`) for async scenarios, where `BufferWriterSlim<T>` cannot be applied because it's **ref struct**. Set the expected upper bound of the written data via the `Capacity` init-only property, because the constructor only accepts the memory allocator: `new PoolingBufferWriter<byte>(allocator) { Capacity = 4096 }`. The buffer grows automatically in case of overflow, but each growth rents a larger buffer, copies the written data and returns the smaller buffer to the pool, where it remains retained. Frequent growth therefore costs copying and inflates the pool, so a good initial capacity matters. - Use `PoolingArrayBufferWriter<T>` (`DotNext.Buffers`) instead when the consumer needs the written data as an array: its `WrittenArray` property returns `ArraySegment<T>`, for example to pass to an API that accepts `byte[]` with offset and count. It rents arrays from `ArrayPool<T>`. - Consider `SparseBufferWriter<T>` (`DotNext.Buffers`) if there is no way to guess the initial capacity, and the contiguous buffer is not a requirement. It chains chunks instead of growing a single buffer, so it never copies the written data on growth. The written memory can be enumerated chunk by chunk (`foreach (ReadOnlyMemory<T> chunk in writer)`), copied with `CopyTo`, or obtained as `System.Buffers.ReadOnlySequence<T>` through its `ISupplier<ReadOnlySequence<T>>` implementation. This type is not limited to bytes in contrast to `RecyclableMemoryStream` from `Microsoft.IO.RecyclableMemoryStream` package. - Write through its public `Write`/`Add` methods only. Its `IBufferWriter<T>` members are implemented explicitly because using them can leave holes in the sparse buffer. - Abstract away memory rental and allocation by using `MemoryAllocator<T>` delegate (`DotNext.Buffers`). It can be passed to the types mentioned above, so your application can be configured to use one of the predefined allocation strategies: - `System.Buffers.ArrayPool<T>.Shared` which is exposed by `MemoryAllocator<T>.Default` static property - Plain array allocation without pooling, which is exposed by `MemoryAllocator<T>.Array` static property - Unmanaged heap allocation, which is exposed by `MemoryAllocator<T>.Unmanaged` static extension property, which requires a reference to `DotNext.Unsafe` package - A custom `ArrayPool<T>` or `MemoryPool<T>` can be converted with the `ToAllocator()` extension method
Voir sur GitHub